STM32F0 Таймер + АЦП не могу заставить корректно работать

Кто любит RISC в жизни, заходим, не стесняемся.
Ответить
Аватара пользователя
pavell
Открыл глаза
Сообщения: 56
Зарегистрирован: Вт дек 29, 2015 11:33:49

STM32F0 Таймер + АЦП не могу заставить корректно работать

Сообщение pavell »

Приветствую всех.
Решил реализовать задачу из разряда "Hello World" - термометр. Реализация с прерывание отлично работает, но (скорее из академического интереса) решил избавится от прерывания и вот тут случилась засада, программа работает совсем не так, как должна. Чувствую что решение где то близко, но видимо знания для решения не хватает.

Ход моих мыслей следующий - таймер TIM3 отсчитывает 5сек, после чего срабатывает триггер, который запускает обработку сигнала от датчика температуры АЦП. В main производится проверка если АЦП закончил преобразование, данные оправляются в функцию, которая вычисляет значение температуры и выводит данные (тут я расписывать ее не стал), после чего последовательность действий должна повториться.

Прошу подскажите где я ошибаюсь?

Код: Выделить всё

void Timer_ini(){
RCC->APB1ENR |= RCC_APB1ENR_TIM3EN;
TIM3->ARR = 48000-1;
TIM3->PSC = 5000;
TIM3->CR2 |= TIM_CR2_MMS_1;     // MMS Update mode
TIM3->DIER |= TIM3_DIER_TIE;
TIM3->CR1 |= TIM_CR1_ARPE;
TIM3->CR1 |= TIM_CR1_CEN;
}  

void ADC_ini(){
RCC->CR2 |= RCC_CR2_HSI14ON;
while (!(RCC->CR2 & RCC_CR2_HSI14RDY));
RCC->APB2ENR = RCC_APB2ENR_ADCEN;
ADC1->CHSELR = ADC_CHSELR_CHSEL16;     //Канал датчика температуры
ADC1->CR |= ADC_CR_ADCAL;              // Калибровка датчика температуры
while ((ADC1->CR & ADC_CR_ADCAL) != 0);
ADC1->SMPR |= ADC_SMPR_SMP_0 | ADC_SMPR_SMP_1 | ADC_SMPR_SMP_2;
ADC1->CFGR1 |= ADC_CFGR1_EXTEN_0;
ADC1->CFGR1 |= ADC_CFGR1_EXTSEL_0 | ADC_CFGR1_EXTSEL_1;     //Выбор триггера TIM3
ADC->CCR |= ADC_CCR_TSEN;
ADC1->CR |= ADC_CR_ADEN;
while ((ADC1->ISR & ADC_ISR_ADRDY) == 0);
ADC1->CR |= ADC_CR_ADSTART;
}

void main(){
 ADC_ini();
 Timer_ini(); 

 while(1){
  if (!(ADC1->ISR & ADC_ISR_EOC)){
    Temp_show(ADC->DR);

//Судя по Reference manual бит EOC должен сбрасываться по прочтению данных из ADC->DR, 
//но этого не происходит, по этой причине добавлен "насильный" сброс
    ADC1->ISR |= ADC_ISR_EOC;
  }
 }
}
Реклама
Аватара пользователя
oleg110592
Друг Кота
Сообщения: 3832
Зарегистрирован: Сб сен 10, 2011 17:46:25

Re: STM32F0 Таймер + АЦП не могу заставить корректно работат

Сообщение oleg110592 »

pavell писал(а):

Код: Выделить всё

RCC->CR2 |= RCC_CR2_HSI14ON;
while (!(RCC->CR2 & RCC_CR2_HSI14RDY));
RCC->APB2ENR = RCC_APB2ENR_ADCEN;
из RM:
The HSI 14 MHz RC oscillator cannot be turned on by ADC interface when the APB clock is selected as an ADC kernel clock.
из примера:

Код: Выделить всё

  /* (1) Enable the peripheral clock of the ADC */
  /* (2) Start HSI14 RC oscillator */ 
  /* (3) Wait HSI14 is ready */
  RCC->APB2ENR |= RCC_APB2ENR_ADC1EN; /* (1) */
  RCC->CR2 |= RCC_CR2_HSI14ON; /* (2) */
  while ((RCC->CR2 & RCC_CR2_HSI14RDY) == 0) /* (3) */
  {
    /* For robust implementation, add here time-out management */
  }  
Реклама
Аватара пользователя
pavell
Открыл глаза
Сообщения: 56
Зарегистрирован: Вт дек 29, 2015 11:33:49

Re: STM32F0 Таймер + АЦП не могу заставить корректно работат

Сообщение pavell »

oleg110592 писал(а): из RM:
В данном случае не суть, можно вообще задать тактирование не от HSI14 :

Код: Выделить всё

ADC1->CFGR2 |= ADC_CFGR2_CKMODE_1; 
RCC->APB2ENR |= RCC_APB2ENR_ADCEN;
Ситуацию это не меняет.
pixar
Потрогал лапой паяльник
Сообщения: 314
Зарегистрирован: Чт ноя 29, 2012 08:27:22

Re: STM32F0 Таймер + АЦП не могу заставить корректно работат

Сообщение pixar »

вот так всё работает , только температуру неправильно показываает. не стал вникать.
Спойлер//
// 2015.12.30
// target: STM32f051_Disco ;
//
#include "stm32f0xx.h"
#include "stm32f0xx_gpio.h"
#include "stm32f0xx_rcc.h"

int32_t volatile static mcu_temperature;

#define LED_C8_ON GPIOC->BSRR = 1<<8
#define LED_C8_OFF GPIOC->BRR = 1<<8
#define LED_C8_TOGGLE GPIOC->ODR ^= ( 1 << 8 )

int32_t Temp_show(uint16_t adc_data);
void ADC_ini(void);
void LED_ini(void);
void Timer_ini();


void ADC_ini(){

RCC->CR2 |= RCC_CR2_HSI14ON;
while (!(RCC->CR2 & RCC_CR2_HSI14RDY));

RCC->APB2ENR = RCC_APB2ENR_ADC1EN; //RCC_APB2ENR_ADCEN

ADC1->CHSELR = ADC_CHSELR_CHSEL16;

ADC1->CR |= ADC_CR_ADCAL;
while ((ADC1->CR & ADC_CR_ADCAL) != 0);

ADC1->SMPR |= ADC_SMPR1_SMPR_0 | ADC_SMPR1_SMPR_1 | ADC_SMPR1_SMPR_2;

ADC1->CFGR1 &= (uint32_t)(~ADC_CFGR1_CONT);

ADC1->CFGR1 |= ADC_CFGR1_EXTEN_0;
ADC1->CFGR1 |= ADC_CFGR1_EXTSEL_0 | ADC_CFGR1_EXTSEL_1;

ADC->CCR |= ADC_CCR_TSEN;

ADC1->CR |= ADC_CR_ADEN;
while ((ADC1->ISR & ADC_ISR_ADRDY) == 0);

ADC1->CR |= ADC_CR_ADSTART;
}



void Timer_ini(void){
RCC->APB1ENR |= RCC_APB1ENR_TIM3EN;
TIM3->PSC = 48000-1;
TIM3->ARR = 5000;
TIM3->CR2 |= TIM_CR2_MMS_1;
//TIM3->DIER |= TIM_DIER_TIE;//TIM3_DIER_TIE;
TIM3->CR1 |= TIM_CR1_ARPE;
TIM3->CR1 |= TIM_CR1_CEN;
}


void main(){

ADC_ini();
Timer_ini();
LED_ini();
LED_C8_ON;

while(1)
{
if ((ADC1->ISR & ADC_ISR_EOC))
{
mcu_temperature = Temp_show(ADC1->DR); // ADC->DR
LED_C8_TOGGLE;
// ADC1->ISR &= ~ADC_ISR_EOC;
}
}// while()
}



void LED_ini(void)
{
GPIO_InitTypeDef InitGpio;

RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE);

InitGpio.GPIO_Pin = GPIO_Pin_8;
InitGpio.GPIO_Mode = GPIO_Mode_OUT;
InitGpio.GPIO_Speed = GPIO_Speed_Level_3;
InitGpio.GPIO_OType = GPIO_OType_PP;
InitGpio.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(GPIOC, &InitGpio);
}


int32_t Temp_show(uint16_t adc_data)
{
#define TEMP110_CAL_ADDR (( uint16_t*) (( uint32_t) 0x1FFFF7C2))
#define TEMP30_CAL_ADDR (( uint16_t*) (( uint32_t) 0x1FFFF7B8))
#define VDD_CALIB (( uint16_t) (325))
#define VDD_APPLI (( uint16_t) (330))

int32_t temperature_c;

//calculate temperature, C^
temperature_c = (((int32_t)adc_data * VDD_APPLI )/ VDD_CALIB)- ( int32_t) *TEMP30_CAL_ADDR ;
temperature_c = temperature_c * ( int32_t)(110 - 30);
temperature_c = temperature_c / ( int32_t)(*TEMP110_CAL_ADDR - *TEMP30_CAL_ADDR);
temperature_c = temperature_c + 30;

return (temperature_c);
}
Реклама
Эиком - электронные компоненты и радиодетали
Аватара пользователя
pavell
Открыл глаза
Сообщения: 56
Зарегистрирован: Вт дек 29, 2015 11:33:49

Re: STM32F0 Таймер + АЦП не могу заставить корректно работат

Сообщение pavell »

pixar писал(а):вот так всё работает ...
В общем то особой разницы с моим кодом не увидел:

Код: Выделить всё

RCC->APB2ENR = RCC_APB2ENR_ADC1EN; //RCC_APB2ENR_ADCEN;
ADC1->SMPR |= ADC_SMPR1_SMPR_0 | ADC_SMPR1_SMPR_1 | ADC_SMPR1_SMPR_2;
из заголовочного файла:

Код: Выделить всё

/*****************  Bit definition for RCC_APB2ENR register  ******************/
#define  RCC_APB2ENR_ADCEN                   ((uint32_t)0x00000200)        /*!< ADC1 clock enable */

/* Old Bit definition maintained for legacy purpose */
#define  RCC_APB2ENR_ADC1EN                  RCC_APB2ENR_ADCEN               /*!< ADC1 clock enable */
Конечно были некоторые описки с моей стороны, типа Temp_show(ADC->DR); вместо ADC1->DR но естественно они были исправлены за долго, ибо с ними компилятор выдал бы ошибки. Справедливости ради стоит отметить, что сделал две поправки из вашего кода - изменил условия по которому запускалась функция Temp_show(); и убрал принудительный сброс бита EOC:

Код: Выделить всё

while(1){
   if ((ADC1->ISR & ADC_ISR_EOC)){      
      Temperature_show(Temerature_calc(ADC1->DR));
   }
}

В конечном итоге увидев, что ваш код из Keil сам установил его и ... все запустилось. Дальше разбираясь с IAR тоже удалось запустить, но тут обнаружилась такая странность - если компилировать, как Release, то не работало, а если как Debuger, то все было отлично, вот такая непонятная пока для меня странность.

Ну и на счет неверной температуры в вашем коде, по всей видимости вы перепутали значения VDD_CALIB и VDD_APPLI первое это напряжение при котором произведена калибровка датчика 3,3В (330), второе напряжение питания.

Мой градусник собственно https://youtu.be/UQJWTz_THm8
Реклама
Ответить

Вернуться в «ARM»