Кто любит RISC в жизни, заходим, не стесняемся.
Ответить

Re: STM32 новичку в ARM что к чему

Ср фев 13, 2019 09:36:58

Уважаемые, подскажите по организации кольцевого буфера.
Для примера возьмем самый распространенный вариант: АЦП -> DMA -> UART.
Создаем буфер размеров 10 байт. После того, как АЦП заполнил первые 5 байт вызывается обработчик прерывания DMA (половина буфера), который эти же первые 5 байт отправляет в UART, параллельно АЦП отправляет вторые 5 байт в буфер. По заполнению буфера вызывается второй обработчик прерывания (полный буфер) который отправляет вторые 5 байт в UART. Пока ход моих мыслей правильный?

Но тут возникает вопрос синхронизации, т.к. ADC->DMA явно быстрее DMA->UART. То возможна ситуация когда АЦП уже заполнил первые 5 байт буфера, а USART еще не отправил вторые 5 байт буфера, как тут поступить?

Re: STM32 новичку в ARM что к чему

Ср фев 13, 2019 11:00:08

Но тут возникает вопрос синхронизации, т.к. ADC->DMA явно быстрее DMA->UART. То возможна ситуация когда АЦП уже заполнил первые 5 байт буфера, а USART еще не отправил вторые 5 байт буфера, как тут поступить?

Для начала нужно четко понять что именно хочется получить, потому что судя по написанному ты хочешь непрерывно отправлять по USART данные которые складываются в буфер быстрее, чем физически их можно оттуда забирать...

Re: STM32 новичку в ARM что к чему

Ср фев 13, 2019 11:07:41

Для начала нужно четко понять что именно хочется получить, ...

Непрерывная передача данных из АЦП в УАРТ посредством DMA

Re: STM32 новичку в ARM что к чему

Ср фев 13, 2019 11:23:48

Непрерывная передача данных из АЦП в УАРТ посредством DMA

Вот, если непрерывная, значит нужно чтобы скорость с которой АЦП складывает данные в буфер была как минимум не больше, а лучше чуть меньше скорости, с которой УАРТ эти данные будет забирать. Значит нужно замедлять АЦП, там есть делитель частоты, десяток фиксированных значений для Sampling time и всегда можно в качестве триггера использовать таймер, тогда скорость может быть практически какой угодно.

Re: STM32 новичку в ARM что к чему

Ср фев 13, 2019 14:03:22

Таймер имеется ввиду пинать АЦП?
Без снижения частоты шины только делителем и выбором времени семплирования АЦП получается самое медленное 126мкс@8МГц. УАРТ - либо 72мкс (115200), либо 138мкс (57600). Если я правильно понимаю, то эта разница времени обработки будет проявляться только в моменты ожидания заполнения буфера и его отправки. И тут чем больше буфер, тем более она заметна?

Re: STM32 новичку в ARM что к чему

Ср фев 13, 2019 14:32:53

Таймер имеется ввиду пинать АЦП?
Без снижения частоты шины только делителем и выбором времени семплирования АЦП получается самое медленное 126мкс@8МГц. УАРТ - либо 72мкс (115200), либо 138мкс (57600). Если я правильно понимаю, то эта разница времени обработки будет проявляться только в моменты ожидания заполнения буфера и его отправки. И тут чем больше буфер, тем более она заметна?

Таймер генерит, например, Update, значит в поле CR2_MMS выбираем соответствующий режим. При этом он пинает АЦП, хоть раз в минуту, для этого нужно указать в поле ADC_CFGR_EXTSEL подходящее событие, сам АЦП при этом может работать с минимальными делителями и временем семплирования. Для начала я бы взял достаточно большой буфер и заполнял его один раз подавая на вход меандр, потом передаешь весь буфер по USART и смотришь что получилось. Если все в порядке, можно пытаться передавать непрерывно, проще наверное оцифровывать медленнее и в прерывании по заполнению половины буфера запускать более быструю отправку. И почему только 115200? 2М должно работать, или даже 2.5М...

Re: STM32 новичку в ARM что к чему

Ср фев 13, 2019 14:41:41

Спасибо, вечером по экспериментирую.

И почему только 115200? 2М должно работать, или даже 2.5М...


Вот я тупанул, STM до 6М позволяет же )

Re: STM32 новичку в ARM что к чему

Ср фев 13, 2019 14:51:00

Вот я тупанул, STM до 6М позволяет же )

Смотря куда передавать, если на комп, то распространенные адаптеры больше 2-2.5M не тянут.

Re: STM32 новичку в ARM что к чему

Чт фев 14, 2019 09:46:04

Привет.
Осваиваю STM32 и столкнулся с проблемой, вроде решил, но не понятно почему она возникает.
Когда меняю частоту ШИМ в процессе выполнения программы
происходит остановка таймера, а через несколько секунд запуск уже с новой частотой.
Меняю вот так в главном цикле:
if(flag){
flag = 0;
TIM2->ARR = new_freq;
}
Проблема уходит если этот код выполнять в обработчике прерывания или а callback функции.
Подскажите почему так происходит, хочется разобраться в причине

Re: STM32 новичку в ARM что к чему

Чт фев 14, 2019 09:53:38

АЦП -> DMA -> UART

Я делал ацп по юарту. У меня было 4 (внешних) ацп с периодом вычитки 20мС. Пробовал гнать по юарту и понял что часть данных бьется. На ПК написал прогу которая из потока данных делала график и там все было четко видно. Это случалось редко, но было критично для анализа работы установки и отловления глюков-багов.
Потом я в посылку прикрепил црц от модбаса и сделал избыточность посылок. А чтобы на ПК различать посылки, еще добавил порядковый номер из одного байта. Вот тогда логирование заработало стабильно. Уложился в 38400.

Re: STM32 новичку в ARM что к чему

Чт фев 14, 2019 10:19:51

TIM2->ARR = new_freq;


TIM2_CR_ARPE бит установлен?

Добавлено after 8 minutes 55 seconds:
АЦП -> DMA -> UART

Я делал ацп по юарту.

Данные напрямую слались из АЦП в УАРТ? Я почему озадачился DMA, у меня данные идут с двух каналов и при пересылке напрямую тоже лагают. CRC он же только для контроля целостности полученного пакета, если же он изначально косячно сформирован то не поможет.

Re: STM32 новичку в ARM что к чему

Чт фев 14, 2019 10:37:54

Проблема уходит если этот код выполнять в обработчике прерывания или а callback функции.

Таймер определяет что досчитал до конца сравнивая текущее значение счетчика с ARR, а не определяя больше ли оно, т.е. если в ARR было 2000 и досчитав до 1000 принудительно записать в ARR 500, то таймер будет считать пока не переполнится, а для 32-х битного таймера это могут быть и минуты. Но все будет нормально если писать в ARR значение больше текущего значения счетчика, или если запись в ARR буферизированна, тогда она происходит при апдейте и счетчик тогда нулевой. То же самое верно для прерывания, тогда счетчик только начинает считать и значение записываемое в ARR наверняка его больше.

Re: STM32 новичку в ARM что к чему

Чт фев 14, 2019 13:05:22

Данные напрямую слались из АЦП в УАРТ? Я почему озадачился DMA, у меня данные идут с двух каналов и при пересылке напрямую тоже лагают. CRC он же только для контроля целостности полученного пакета, если же он изначально косячно сформирован то не поможет.

Да нет. Там СПИ, вычитка, контроль состояний, аварий и т.п. И только потом ЮАРТ.

Добавлено after 4 minutes 3 seconds:
CRC он же только для контроля целостности полученного пакета, если же он изначально косячно сформирован то не поможет.

А как это можно "изначально косячно сформировать CRC"? Црц он и есть црц, процом прощитан и к посылке прикреплен. Если в приемнике не сошлось - отбрасываем пакет. Передеча исбыточная - 2-4 одинаковых пакета подряд. Если приемник пакет принял, то запоминает его номер и дальше такие же номера отбрасываем.

Добавлено after 4 minutes 12 seconds:
Кстати, для разделения пакетов я не использовал никаких таймаутов - данные идут сплошным потоком. ПК знает длину посылки и по шаблону ищет совпадение пакета и црц, двигается по 1му байту и убирает из буффера, пока не найдет пакет. Дальше получается автоматическая синхронизация - отрезаем по целому пакету, пока не случится сбой, потом опять по 1му байту и т.д.
Если тулить таймауты то в 38400 не укладывался.

Re: STM32 новичку в ARM что к чему

Чт фев 14, 2019 17:12:51

TIM2_CR_ARPE бит установлен?

И с ним и без него пробовал, разницы особо не заметил. Насколько я знаю это помогает от кривых имульсов при изменении частоты, у меня же несколько иная ситуация
для 32-х битного таймера это могут быть и минуты. Но все будет нормально если писать в ARR значение больше текущего значения счетчика

Кстати да, проблема проявляется когда я записываю в ARR меньшее значение чем там было. Причем проявляется не всегда.
Чем больше разница между текущим и новым (меньшим значениям) тем больше вероятность глюка.
Например было 20 000, стало 18 000 глюк будет очень редко, было 20 000, стало 3000, глюк будет почти наверняка.
Тупо срыв генерации или низкий или высокий уровень устанавливается на ножке МК.
Но таймер у меня 16 битный без делителя, на 48 МГц работает, частоту только с помощью регистра сравнения меняю, поэтому доситывать до переполнения будет быстро.
Здесь что то другое.

Re: STM32 новичку в ARM что к чему

Чт фев 14, 2019 17:38:53

Чем больше разница между текущим и новым (меньшим значениям) тем больше вероятность глюка.
Например было 20 000, стало 18 000 глюк будет очень редко, было 20 000, стало 3000, глюк будет почти наверняка.

Так правильно, если изменять ARR в произвольное время, то в первом случае глюк будет наблюдаться только когда счетчик больше 18K, т.е. с вероятностью 1/10. А во-втором случае все практически наоборот...

Но таймер у меня 16 битный без делителя, на 48 МГц работает, частоту только с помощью регистра сравнения меняю, поэтому доситывать до переполнения будет быстро.
Здесь что то другое.

Скорее не другое, а что-то еще :) Но решение уже озвучивали, включение CR1_ARPE должно помочь.

Кстати, что за мк? 48 MHz как бы намекают на F0, а там TIM2 32-х битный.

Re: STM32 новичку в ARM что к чему

Вс фев 17, 2019 16:21:35

Что-то не срастается моя идея ADC->DMA->UART. Судя по отладчику данные бегают, а вот прерывания не обрабатываться. Может кто подскажет что не так?
Спойлер
Код:
#include "stm32f0xx.h"

uint16_t buff[100];


void DMA1_Channel1_IRQHandler(void){
   //empty   
}

void DMA1_Channel2_3_IRQHandler(void){
   //empty
}

void gpio_ini(){
   RCC->AHBENR |= RCC_AHBENR_GPIOBEN;
   GPIOB->MODER |= GPIO_MODER_MODER6_1 | GPIO_MODER_MODER0 | GPIO_MODER_MODER1;
   GPIOB->OTYPER &= ~GPIO_OTYPER_OT_6;
   GPIOB->PUPDR &= ~GPIO_PUPDR_PUPDR6_0;
   GPIOB->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR6;
   GPIOB->AFR[0] &= ~GPIO_AFRL_AFRL6;   
}

void usart_ini(){
   RCC->APB2ENR |= RCC_APB2ENR_USART1EN;
   USART1->BRR = SystemCoreClock/256000;
   USART1->CR3 = USART_CR3_DMAT;
   USART1->CR1 |= USART_CR1_TE;
   USART1->CR1 |= USART_CR1_TCIE;
   USART1->CR1 |= USART_CR1_UE;
}

void adc_ini(){
   RCC->APB2ENR |= RCC_APB2ENR_ADCEN;
   ADC1->CHSELR |= ADC_CHSELR_CHSEL8 | ADC_CHSELR_CHSEL9;   
   ADC1->SMPR  |= ADC_SMPR_SMP_2 | ADC_SMPR_SMP_0;          
   ADC1->CFGR2 |= ADC_CFGR2_CKMODE_1;   
   ADC1->CFGR1 &= ~ADC_CFGR1_SCANDIR;   
   ADC1->CFGR1 |= ADC_CFGR1_CONT;
   ADC1->CFGR1 &= ~ADC_CFGR1_RES_Msk;
   ADC1->CFGR1 |= ADC_CFGR1_DMACFG;
   ADC1->CFGR1 |= ADC_CFGR1_DMAEN;
   
   ADC1->CR |= ADC_CR_ADCAL;
      while(ADC1->CR & ADC_CR_ADCAL){
   }
   
   ADC1->CR |= ADC_CR_ADEN;
}

void dma_ini(){
   RCC->AHBENR |= RCC_AHBENR_DMAEN;
   
// DMA1 ADC->DMA init
   DMA1_Channel1->CPAR |= (uint32_t)&ADC1->DR;
   DMA1_Channel1->CMAR |= (uint32_t)&buff[0];
   DMA1_Channel1->CNDTR |= 100;
   DMA1_Channel1->CCR &= ~DMA_CCR_MEM2MEM_Msk;
   DMA1_Channel1->CCR &= ~DMA_CCR_DIR;   
   DMA1_Channel1->CCR &= ~DMA_CCR_PL_Msk;
   DMA1_Channel1->CCR |= DMA_CCR_MSIZE_0;
   DMA1_Channel1->CCR |= DMA_CCR_PSIZE_0;
   DMA1_Channel1->CCR |= DMA_CCR_MINC;
   DMA1_Channel1->CCR |= DMA_CCR_CIRC;
   DMA1_Channel1->CCR |= DMA_CCR_HTIE;
   DMA1_Channel1->CCR |= DMA_CCR_TCIE;
   DMA1_Channel1->CCR |= DMA_CCR_EN;
   NVIC_EnableIRQ(DMA1_Channel1_IRQn);
   NVIC_SetPriority(DMA1_Channel1_IRQn,2);

// DMA2 DMA->UART init
   DMA1_Channel2->CPAR |= (uint32_t)&USART1->TDR;
   DMA1_Channel2->CMAR |= (uint32_t)&buff[0];
   DMA1_Channel2->CNDTR |= 100;
   DMA1_Channel2->CCR &= ~DMA_CCR_MEM2MEM_Msk;
   DMA1_Channel2->CCR |= DMA_CCR_DIR;
   DMA1_Channel2->CCR &= ~DMA_CCR_PL_0;
   DMA1_Channel2->CCR &= ~DMA_CCR_MSIZE_Msk;
   DMA1_Channel2->CCR &= ~DMA_CCR_PSIZE_Msk;
   DMA1_Channel2->CCR |= DMA_CCR_MINC;
   DMA1_Channel2->CCR |= DMA_CCR_CIRC;
   DMA1_Channel2->CCR |= DMA_CCR_HTIE;
   DMA1_Channel2->CCR |= DMA_CCR_TCIE;
   DMA1_Channel2->CCR |= DMA_CCR_EN;
   NVIC_EnableIRQ(DMA1_Channel2_3_IRQn);
   NVIC_SetPriority(DMA1_Channel2_3_IRQn,1);   
}

int main(){
   void __enable_irq(void);
   NVIC->ISER[0] = 0x03<<7;
   
   dma_ini();
   gpio_ini();
   adc_ini();
   usart_ini();
   

   ADC1->CR |= ADC_CR_ADSTART;
   while(1){
      //empty
   }
   return 0;
}

Re: STM32 новичку в ARM что к чему

Ср фев 20, 2019 12:19:47

Код:
DMA1_Channel1->CPAR |= (uint32_t)&ADC1->DR;
   DMA1_Channel1->CMAR |= (uint32_t)&buff[0];
   DMA1_Channel1->CNDTR |= 100;


Обычные ляпы?

Re: STM32 новичку в ARM что к чему

Ср фев 20, 2019 15:03:27

Да ему "так наглядней" :)

Re: STM32 новичку в ARM что к чему

Ср фев 20, 2019 15:53:09

Да ему "так наглядней"

Не угадали, Владислав.

dosikus писал(а):Обычные ляпы?

Хуже, невнимательность.

Re: STM32 новичку в ARM что к чему

Чт фев 21, 2019 07:57:05

Не угадали, Владислав.
Да тут и гадать не надо.
У того кто вот так &buff[0] берёт адрес массива и особенно автора вот этого
Код:
   DMA1_Channel1->CCR &= ~DMA_CCR_MEM2MEM_Msk;
   DMA1_Channel1->CCR &= ~DMA_CCR_DIR;   
   DMA1_Channel1->CCR &= ~DMA_CCR_PL_Msk;
   DMA1_Channel1->CCR |= DMA_CCR_MSIZE_0;
   DMA1_Channel1->CCR |= DMA_CCR_PSIZE_0;
   DMA1_Channel1->CCR |= DMA_CCR_MINC;
   DMA1_Channel1->CCR |= DMA_CCR_CIRC;
   DMA1_Channel1->CCR |= DMA_CCR_HTIE;
   DMA1_Channel1->CCR |= DMA_CCR_TCIE;
   DMA1_Channel1->CCR |= DMA_CCR_EN;
большие проблемы. :(
Ответить