Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: STM32L051K8T6 + SysTick + ADC
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
Борис 1984
Добрый день, товарищи!

У меня такая проблема: настраиваю системный таймер с периодом 10мкс и АЦП с периодом преобразования 50 мкс, по отдельности все работает нормально. Когда вместе, при одинаковых приоритетах прерываний на осциллографе вижу только работу таймера, если у АЦП выше приоритет, то есть пропуски прерываний от таймера, т.е. между входами t = 20мкс. Тактирую от HSI. Проверяю это с помощью светодиода и сигнала на лапах.
CODE
void Init()
{

//------ System clock HSI = 16 MHz ----------------------------------------

// FLASH->ACR = 0x00000001;

RCC->CFGR = RCC_CFGR_SW_HSI;// | RCC_CFGR_PPRE2_DIV16;
RCC->CR = RCC_CR_HSION | RCC_CR_HSIDIVEN; // Âíóòðåííèé ãåíåðàòîð ñ äåëèòåëåì íà 4

while(!(RCC->CR & RCC_CR_HSIRDY)) ; // Îæèäàíèå ñòàáèëèçàöèè ÷àñòîòû âíóòðåííåãî ãåíåðàòîðà

while(!(RCC->CR & RCC_CR_HSIDIVF)) ;


RCC->IOPENR = RCC_IOPENR_GPIOAEN | RCC_IOPENR_GPIOBEN; // Òàêòèðîâàíèå ïîðòîâ À è Â
RCC->APB2ENR = RCC_APB2ENR_ADC1EN; // Òàêòèðîâàíèå ÀÖÏ

GPIOA->MODER = 0xE85EFDDF;
GPIOA->PUPDR = 0x25000000;

GPIOB->MODER = 0xFFFFDFFF;

ADC1->CR |= ADC_CR_ADCAL;
while(ADC1->CR & ADC_CR_ADCAL) ; // Îæèäàíèå îêîí÷àíèÿ êàëèáðîâêè

ADC1->IER |= ADC_IER_EOCIE; // Ðàçðåøåíèå ïðåðûâàíèÿ ïî çàâåðøåíèè ïðåîáðàçîâàíèÿ
ADC1->CFGR1 |= ADC_CFGR1_WAIT | ADC_CFGR1_CONT;
ADC1->CFGR2 |= ADC_CFGR2_OVSR_0 | ADC_CFGR2_OVSR_1;
ADC1->CHSELR |= ADC_CHSELR_CHSEL3; // 3 êàíàë - ïðèåìíèê
ADC1->SMPR = ADC_SMPR_SMPR;
ADC->CCR |= ADC_CCR_LFMEN; // Low Frequency Mode
ADC1->CR = ADC_CR_ADSTART | ADC_CR_ADEN;


//----------------------SysTick Timer--------------------------------
SysTick->LOAD = 5;
// NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1); /* set Priority for Systick Interrupt */
SysTick->VAL = 0;
SysTick->CTRL |= 0x07;

// NVIC_SetPriority(ADC1_COMP_IRQn, (1<<__NVIC_PRIO_BITS) - 1);
NVIC_EnableIRQ(ADC1_COMP_IRQn);
}
//-------------------------------------------
void SysTick_Handler(void) // 10 ìêñ
{
f_blink ^= 0x01;
if(f_blink)
GREEN_LED_ON;
else
GREEN_LED_OFF;
}
//-------------------------------------------
void ADC1_COMP_IRQHandler()
{
uint16_t resADC = ADC1->DR;

f_blink1 ^= 0x01;
if(f_blink1)
RED_LED_ON;
else
RED_LED_OFF;
}

Подскажите, пожалуйста в чем проблема.
adnega
Цитата
SysTick->LOAD = 5;


16M / 8 / 5 -> 2.5 мкс

Другими словами прерывание происходит каждые 40 тактов проца. Ну что за такое время можно успеть?


Проверил по документации
Цитата
SysTick->CTRL |= 0x07;


Вообще 5 тактов, т.к. предделитель для SysTick отключается.
Борис 1984
Цитата(adnega @ Sep 23 2014, 10:17) *
16M / 8 / 5 -> 2.5 мкс

Другими словами прерывание происходит каждые 40 тактов проца. Ну что за такое время можно успеть?


Не совсем понял?
Как я понимаю частота тактирования таймера HCLK/8 с предделителем /4 - T=500 кГц или 2мкс на счет. При загрузке значени 5 в LOAD - срабатывание будет через 10мкс - я это вижу на осциллографе, когда АЦП отключено

Цитата(adnega @ Sep 23 2014, 10:32) *
Проверил по документации


Вообще 5 тактов, т.к. предделитель для SysTick отключается.



Для серии L0 всегда HCLK/8 я проверил и CubeMX в Clock Configuration так показывает! Делитель нельзя отключить!!!
adnega
Цитата(Борис 1984 @ Sep 23 2014, 10:50) *
Для серии L0 всегда HCLK/8 я проверил и CubeMX в Clock Configuration так показывает! Делитель нельзя отключить!!!

В документе "PM0223 STM32L0 Series Cortex®-M0+ programming manual"
STK_CSR:
Цитата
Bit 2 CLKSOURCE Selects the SysTick timer clock source:
0 = External reference clock.
1 = Processor clock.


Попробуйте увеличить LOAD до 200-1 и посмотреть за периодом. Должен быть 100 мкс.

16M(HSI) / 4(HSIDIV4) / 200(LOAD) / 2(BLINK on-off) = 100 мкс.
scifi
Цитата(Борис 1984 @ Sep 23 2014, 09:32) *
настраиваю системный таймер с периодом 10мкс

Какой ужас. Зачем 10 мкс? Обычно бывает 10 мс. А если 10 мкс, то велик риск "что-нибудь не успеть", как справедливо замечено выше.
Борис 1984
Спасибо!
Похоже все дело в том что МК не успевает обрабатывать прерывания на таких частотах, появляются пропуски, сейчас попробую поднять частоту через PLL.

Цитата(scifi @ Sep 23 2014, 14:23) *
Какой ужас. Зачем 10 мкс? Обычно бывает 10 мс. А если 10 мкс, то велик риск "что-нибудь не успеть", как справедливо замечено выше.


Нужна программная реализация высокоскоростного протокола обмена.
scifi
Цитата(Борис 1984 @ Sep 23 2014, 14:30) *
Нужна программная реализация высокоскоростного протокола обмена.

Ну тогда нужно внимательно следить, чтобы всё действительно успевало выполняться. Иначе могут полезть загадочные глюки.
adnega
Цитата(Борис 1984 @ Sep 23 2014, 14:30) *
Нужна программная реализация высокоскоростного протокола обмена.

А что за протокол?
А почему бы не приспособить для этого периферийные блоки?
А какой кайф от L-серии в такой "программной реализации"?
Борис 1984
Цитата(adnega @ Sep 23 2014, 14:38) *
А что за протокол?
А почему бы не приспособить для этого периферийные блоки?
А какой кайф от L-серии в такой "программной реализации"?


Протокол собственной разработки, передача последовательностей 8-10 бит, длительность бита 250мкс.
Серия L выбрана, как низко потребляющая.
Можете подробнее рассказать, какие периферийные блоки можно использовать?
scifi
Цитата(Борис 1984 @ Sep 23 2014, 15:52) *
Можете подробнее рассказать, какие периферийные блоки можно использовать?

SPI+DMA, к примеру.
adnega
Цитата(Борис 1984 @ Sep 23 2014, 15:52) *
Протокол собственной разработки, передача последовательностей 8-10 бит, длительность бита 250мкс.
Серия L выбрана, как низко потребляющая.
Можете подробнее рассказать, какие периферийные блоки можно использовать?

А какой именно протокол? Можно в UART или SPI превратить? Если нет, то "плохой"))
В крайнем случае можно завести на таймер и генерить одно прерывание на бит аппаратно (делал для ИК-приемника, 1-wire, wiegand т.п.).
Чтобы проц мало потреблял, софт должен отвечать нескольким требованиям. Самое главное, он все время должен спать.
А софтовая обработка с дискретизацией 10 мкс спать процу не даст.
Mihey_K
Интересно, что за задачу решаете с таким мизерными квантами времени. И сильно сомневаюсь, что с подобными временными окнами удастся на Cortex-M все реализовать без гонки событий, тут больше ПЛИС напрашивается.
scifi
Цитата(Mihey_K @ Sep 23 2014, 16:28) *
Интересно, что за задачу решаете с таким мизерными квантами времени. И сильно сомневаюсь, что с подобными временными окнами удастся на Cortex-M все реализовать без гонки событий, тут больше ПЛИС напрашивается.

Не нужно пугать раньше времени. 10 мкс - это 320 тактов. Вполне можно сделать что-то осмысленное, если не сильно тупить.
adnega
Цитата(scifi @ Sep 23 2014, 16:45) *
Не нужно пугать раньше времени. 10 мкс - это 320 тактов. Вполне можно сделать что-то осмысленное, если не сильно тупить.

А если учесть, что бит 250 мкс. А пачки 8-10 бит, то хитровывернутая настройка аппаратных блоков вообще может свести этот показатель до рубежа 40 000 тактов @ 16МГц. Причем 40 000 тактов во сне)
Борис 1984
Цитата(adnega @ Sep 23 2014, 16:05) *
А какой именно протокол? Можно в UART или SPI превратить? Если нет, то "плохой"))
В крайнем случае можно завести на таймер и генерить одно прерывание на бит аппаратно (делал для ИК-приемника, 1-wire, wiegand т.п.).
Чтобы проц мало потреблял, софт должен отвечать нескольким требованиям. Самое главное, он все время должен спать.
А софтовая обработка с дискретизацией 10 мкс спать процу не даст.


Протокол - аналог SystemSensors.
Попробовал поднять частоту с помощью PLL до 32МГц - помогло, но пока не знаю что с потреблением в итоге получится.
Все спасибо за помощь, среди постов есть интересные мысли.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.