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

Кто любит RISC в жизни, заходим, не стесняемся.
Ответить
Друг Кота
Аватара пользователя
Сообщения: 4905
Зарегистрирован: Чт апр 11, 2013 11:19:59
Откуда: Минск

Сообщение WiseLord »

А не может ли здесь произойти так, что CurrentChannel поменялся с 1 на 2, а EOSEQ флаг остался равен 0 (не успел, например, выставиться)?

Соотвественно, сброс индекса в 0 не происходит на этой итерации, происходит ещё одна, когда данные пишутся в ADC_array[2], по сути, портя память.

Ну и сдвиг каналов происходит при этом.

Я бы в этом коде не стал надеятся на то, что ADC_ISR_EOSEQ будет в нужном состоянии, как только будет прочитан последний канал в последовательности. Вещи-то по сути не связанные.
Контактная информация:
Реклама
Потрогал лапой паяльник
Аватара пользователя
Сообщения: 363
Зарегистрирован: Вс мар 03, 2019 08:18:34
Откуда: Волгоград

Сообщение do-vitas »

Да так все и происходит. Только как это обыграть не пойму. У ф0 серии нет режекционных коналов..
Реклама
Друг Кота
Аватара пользователя
Сообщения: 25484
Зарегистрирован: Чт янв 10, 2008 22:01:02
Откуда: Московская область, Фрязино

Сообщение КРАМ »

[uquote="do-vitas",url="/forum/viewtopic.php?p=4464499#p4464499"]нет режекционных коналов..[/uquote]
Инжектированных.
Друг Кота
Аватара пользователя
Сообщения: 4905
Зарегистрирован: Чт апр 11, 2013 11:19:59
Откуда: Минск

Сообщение WiseLord »

Ну, как минимум, сброс счётчика каналов сделать самостоятельным и независящим от флагов:

Может, как-то так:

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

while ((ADC1->ISR & ADC_ISR_EOC) == 0) /* wait end of conversion */
{
/* For robust implementation, add here time-out management */
}

if ((ADC1->ISR & ADC_ISR_EOC) != 0)         /* checks EOC has triggered the IT */
{
    ADC_array[CurrentChannel] = ADC1->DR;   /* reads data and clears EOC flag */
    CurrentChannel++;                       /* increments the index on ADC_array */
    
    if (CurrentChannel >= 2) {
        CurrentChannel = 0; /* reinitialize the CurrentChannel */
        out_adc = ADC_array[0];in_adc = ADC_array[1];
    }
}

if ((ADC1->ISR & ADC_ISR_EOSEQ) != 0)       /* checks EOSEQ has triggered the IT */
{
    ADC1->ISR |= ADC_ISR_EOSEQ;             /* clears the pending bit */
}
Контактная информация:
Реклама
Эиком - электронные компоненты и радиодетали
Мучитель микросхем
Сообщения: 446
Зарегистрирован: Вс ноя 01, 2015 09:15:16
Откуда: 69.Ржев

Сообщение a797945 »

будем полагать, что не знаем какой канал сейчас оцифровывается, поэтому считав DR проверяем EOSEQ - если 1 то это последний в очереди. и я полагаю, что в последующем это все таки массив (с чередованием каналов) - иначе зачем массив, это просто две переменные.
Реклама
Потрогал лапой паяльник
Аватара пользователя
Сообщения: 363
Зарегистрирован: Вс мар 03, 2019 08:18:34
Откуда: Волгоград

Сообщение do-vitas »

a797945, да в том и проблема, что как писал WiseLord, тот самый EOSEQ то взлетает а то нет. я конечно решил проблему при помощи костыля: каждый раз перед запуском преобразования, меняю значение регистра ADC1->CFGR1 |= ADC_CFGR1_SCANDIR что меняет направление сканирования каналов ацп, но осадчик остался, а если больше 2-х каналов...
Реклама
Мучитель микросхем
Сообщения: 446
Зарегистрирован: Вс ноя 01, 2015 09:15:16
Откуда: 69.Ржев

Сообщение a797945 »

выстраивайте ожидание:
1 снимаем флаг EOSEQ, если был
2 ждем когда EOSEQ=1 - текущая очередь заканчивается,
3 снимаем флаги EOSEQ, EOC ,
4 ждем EOC первого из новой очереди
...

да и очередь лучше как-то так задавать (не через |=)
ADC1->CHSELR = ADC_CHSELR_CHSEL2 | ADC_CHSELR_CHSEL5;
Потрогал лапой паяльник
Аватара пользователя
Сообщения: 363
Зарегистрирован: Вс мар 03, 2019 08:18:34
Откуда: Волгоград

Сообщение do-vitas »

[uquote="a797945",url="/forum/viewtopic.php?p=4464619#p4464619"]выстраивайте ожидание:

да и очередь лучше как-то так задавать (не через |=)
ADC1->CHSELR = ADC_CHSELR_CHSEL2 | ADC_CHSELR_CHSEL5;[/uquote]
нет разницы какой тут порядок, он идут по порядку, а ADC_CFGR1_SCANDIR определят только напряжение от большего к меньшему либо наоборот.
Мучитель микросхем
Сообщения: 446
Зарегистрирован: Вс ноя 01, 2015 09:15:16
Откуда: 69.Ржев

Сообщение a797945 »

а если посмотреть, действительно EOSEQ пропадает ?

ADC_array[128]=0;

ADC1->ISR |=ADC_ISR_EOC | ADC_ISR_EOSEQ;
for (int i; i<128; i++){

while ((ADC1->ISR & ADC_ISR_EOC) == 0) {}
ADC1->ISR |=ADC_ISR_EOC;

if (ADC1->ISR & ADC_ISR_EOSEQ) {
ADC1->ISR |= ADC_ISR_EOSEQ;
ADC_array = 1;}
else {ADC_array = 0;}
}
если в очереди 2 канала - в массиве ожидается зебра (0,1,0, ...) без пропусков
отредактировал, тороплюсь куда-то.
Родился
Сообщения: 4
Зарегистрирован: Вт авг 29, 2023 13:45:38

Сообщение engine66 »

Здравствуйте!
Вопрос по STM32F103C8
Хочу настроить ADC следующим образом" 8 каналов - медленные (датчики давления, температуры и т. п.) и два канала для оцифровки звука.
Представился такой вариант: Двойным преобразованием ADC1 и ADC2 c DMA с регулярных каналов заполнять массив датчиков 4Х2 непрерывно без прерываний вообще. Считывать их в свободное время. Плюс для оцифровки звука два инжектированных канала, также двойным преобразованием ADC1 и ADC2, периодически запускать по таймеру и считывать результат в прерывании от ADC по завершению преобразования. Можно так сконфигурировать Blue Pill? Или есть другие варианты попроще?
Родился
Сообщения: 4
Зарегистрирован: Вт авг 29, 2023 13:45:38

Сообщение engine66 »

Частота дискретизации звука (приём тональных сигналов) выбрана 14080. Получается 852 такта ADC между прерываниями таймера для старта преобразования ижектированных каналов. Если sampling time выставить максимальным 239,5, то в этот промежуток укладываются три преобразования - один инжектированный (два канала) и два регулярных (четыре канала). Вроде проблем нет.
Друг Кота
Аватара пользователя
Сообщения: 25484
Зарегистрирован: Чт янв 10, 2008 22:01:02
Откуда: Московская область, Фрязино

Сообщение КРАМ »

[uquote="engine66",url="/forum/viewtopic.php?p=4470649#p4470649"]Представился такой вариант: Двойным преобразованием ADC1 и ADC2 c DMA с регулярных каналов заполнять массив датчиков 4Х2 непрерывно без прерываний вообще. Считывать их в свободное время. Плюс для оцифровки звука два инжектированных канала, также двойным преобразованием ADC1 и ADC2[/uquote]
Все поставлено с ног на голову... :facepalm:
Под ДМА должен работать звук, а не датчики. А датчики можно считывать в прерываниях. Они медленные и потому редкие.
Только вот возник вопрос. А куда потом этот звук?
Родился
Сообщения: 4
Зарегистрирован: Вт авг 29, 2023 13:45:38

Сообщение engine66 »

КРАМу
Спасибо за отклик. Звук не под DMA так как планируются некоторые вычисления после приёма каждого сэмпла. это будут команды тональными сигналами, по полсекунды длиной. Думаю использовать синхронное детектирование, для простоты и кажется минимум ресурсов понадобится на вычисления.
А датчики под DMA для того же, чтобы минимум ресурсов на них тратить. Как-то так.

Добавлено after 13 minutes 58 seconds:
То есть процесс будет выглядеть примерно так: Сканируются два оегулярных преобразования и складываются куда надо под ДМА без прерываний, затем как только начинается третье регулярное преобразование, оно прерывается инжектированным преобразованием, данные которого извлекаются через прерывание. После окончания инжектированного преобразования, сканируются третье и четвёртое регулярные преобразования, а как только вновь начинается первое, оно прерывается на инжектированное преобразование и так дальше.
Друг Кота
Аватара пользователя
Сообщения: 25484
Зарегистрирован: Чт янв 10, 2008 22:01:02
Откуда: Московская область, Фрязино

Сообщение КРАМ »

[uquote="engine66",url="/forum/viewtopic.php?p=4471168#p4471168"]Звук не под DMA так как планируются некоторые вычисления после приёма каждого сэмпла. это будут команды тональными сигналами, по полсекунды длиной.[/uquote]
Так и принимайте окнами. Тональные сигналы - это классический ДПФ приемник. Окно приема должно иметь длину рассчитанную из полосы пропускания фильтров. В зависимости от оконной функции оно будет немного больше чем величина обратная полосе фильтра. Скажем, для полосы в 100 Гц окно потребуется примерно 12...15 мс. При частоте дискретизации, например, 8 кГц количество отсчетов в одном окне составит примерно 128. Захватили окно - сделали N-канальный ДПФ - обнаружили сигнал - приняли решение. За полсекунды можно накопить аж 32 окна и получить 32 скалярных значения фильтров. Ну и зачем вам обрабатывать каждый отсчет? :dont_know:
Скажу больше. У АРМов прерывания - полный тормоз. Вы получите на каждом отсчете кучу потерянного времени на вход-сохранение контекста-восстановление контекста-выход... Оно вам зачем?
Родился
Сообщения: 4
Зарегистрирован: Вт авг 29, 2023 13:45:38

Сообщение engine66 »

КРАМу
Вот так вот обрубили полёт моей фантазии )
ОК, выберу какое-нибудь классическое решение.
Друг Кота
Аватара пользователя
Сообщения: 25484
Зарегистрирован: Чт янв 10, 2008 22:01:02
Откуда: Московская область, Фрязино

Сообщение КРАМ »

Обращайтесь, если что...
:)
Мучитель микросхем
Сообщения: 446
Зарегистрирован: Вс ноя 01, 2015 09:15:16
Откуда: 69.Ржев

Сообщение a797945 »

если интересует тон - зачем АЦП ?
Друг Кота
Аватара пользователя
Сообщения: 25484
Зарегистрирован: Чт янв 10, 2008 22:01:02
Откуда: Московская область, Фрязино

Сообщение КРАМ »

Ну наверное потому, что детектировть DTMF с помощью АЦП проще, чем городить разного рода суррогаты, рискуя получить всякий бред при помехах.
Встал на лапы
Аватара пользователя
Сообщения: 104
Зарегистрирован: Пн ноя 04, 2019 09:58:29
Откуда: г. Нижний Тагил Свердл. обл.

Сообщение Эйлер Леонард »

Добрый день. Решил на досуге заняться портированием драйвера АЦП ADS1256, который написан для STM32 (С) на 8-и битную архитектуру ATmega(С++14). Но вот оказия - в STM32 не петрю. А драйверок то хороший, полнофункциональный - есть все, что надо и ни чета Ардуиновским библиотекам. Вопрос мой конечно немного глуповатый: Регистр данный в SPI на STM32 тридцатидвухбитный? У мег 8-битный. И для передачи/приема чисел более 8-и бит на AVR-ках их передают кусочками по 8 бит, а потом уже склеивают в одно число. Для АЦП ADS1256 необходимы определенные тайминги при общении с МК по SPI. Напр. отправил 8 бит - перекур в несколько тактов(или микросекунд). Вот по этому и вкрались сомнения по необходимости таймингов после отправки каждого байта.
Регистр данный в SPI на STM32 тридцатидвухбитный?
это для мег
Спойлер

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

#define NOP __asm__ __volatile__ ("nop");
inline static uint32_t transfer24(uint32_t data) {
	union {
		uint32_t val;
		struct { uint8_t lsb, mid, msb; };
	} in, out;
	
	in.val = data;
	
	if(SPCR & bit(DORD)){ // прямой порядок отправки
		
		SPDR = in.lsb; // младший
		NOP;
		while(!( SPSR & bit(SPIF) )){}; //wait
		out.lsb = SPDR;

		SPDR = in.mid; // средний
		NOP;
		while(!( SPSR & bit(SPIF) )){}; //wait
		out.mid = SPDR;

		SPDR = in.msb; // старший
		NOP;
		while(!( SPSR & bit(SPIF) )){}; //wait
		out.msb = SPDR;
		
		} else { // обратный порядок отправки
		
		SPDR = in.msb; // старший
		NOP;
		while(!( SPSR & bit(SPIF) )){}; //wait
		out.msb = SPDR;

		SPDR = in.mid; // средний
		NOP;
		while(!( SPSR & bit(SPIF) )){}; //wait
		out.mid = SPDR;
		
		SPDR = in.lsb; // младший
		NOP;
		while(!( SPSR & bit(SPIF) )){}; //wait
		out.lsb = SPDR;
		
	}
	
	return (out.val);

}
Друг Кота
Аватара пользователя
Сообщения: 3716
Зарегистрирован: Чт мар 07, 2013 20:39:17
Откуда: Краснодар

Сообщение asvhmao »

Камень stm32f103cb
В ардуинке попался код настройки таймера TIM1 с первым каналом. Хотел поиграть со всеми четырьмя каналами, с инверсией и выравниванию по центру. Три канала работают, четвёртый не хотит, CHxN тоже молчит.
Где накосячил, пока не разобрался :dont_know:
Опыта с регистрами всего пару дней.

Изображение
Спойлер

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

#include "flprogUtilites.h"
int16_t Timperiod;
int16_t PWM_1;
int16_t PWM_2;
int16_t PWM_3;
int16_t PWM_4;
int16_t Fr;
bool Q;
#define RCC_BASE 0x40021000
#define RCC_APB2ENR ((volatile uint32_t *)(RCC_BASE+0x18))
#define GPIOA_BASE 0x40010800
#define GPIOA_CRH ((volatile uint32_t *)(GPIOA_BASE+0x04))
#define GPIOB_BASE 0x40010C00
#define GPIOB_CRH ((volatile uint32_t *)(GPIOB_BASE+0x04))
#define TIM1_BASE 0x40012C00
#define TIM1_CNT ((volatile uint32_t *)(TIM1_BASE+0x24))
#define TIM1_CR1 ((volatile uint32_t *)(TIM1_BASE+0x00))
#define TIM1_CCMR1 ((volatile uint32_t *)(TIM1_BASE+0x18))
#define TIM1_CCMR2 ((volatile uint32_t *)(TIM1_BASE+0x1C))
#define TIM1_CCER ((volatile uint32_t *)(TIM1_BASE+0x20))
#define TIM1_PSC ((volatile uint32_t *)(TIM1_BASE+0x28))
#define TIM1_ARR ((volatile uint32_t *)(TIM1_BASE+0x2C))
#define TIM1_CCR1 ((volatile uint32_t *)(TIM1_BASE+0x34))
#define TIM1_CCR2 ((volatile uint32_t *)(TIM1_BASE+0x38))
#define TIM1_CCR3 ((volatile uint32_t *)(TIM1_BASE+0x3C))
#define TIM1_CCR4 ((volatile uint32_t *)(TIM1_BASE+0x40))
#define TIM1_BDTR ((volatile uint32_t *)(TIM1_BASE+0x44))
uint16_t test= 0;
uint16_t PWMcontrol= 0;
#define TIM1_CCER ((volatile uint32_t *)(TIM1_BASE+0x20))
#define TIM1_PSC ((volatile uint32_t *)(TIM1_BASE+0x28))
#define TIM1_ARR ((volatile uint32_t *)(TIM1_BASE+0x2C))
#define TIM1_CCR1 ((volatile uint32_t *)(TIM1_BASE+0x34))
#define TIM1_CCR2 ((volatile uint32_t *)(TIM1_BASE+0x38))
#define TIM1_CCR3 ((volatile uint32_t *)(TIM1_BASE+0x3C))
#define TIM1_CCR4 ((volatile uint32_t *)(TIM1_BASE+0x40))
#define TIM1_BDTR ((volatile uint32_t *)(TIM1_BASE+0x44))
int16_t _gtv2;
void setup()
{
    *RCC_APB2ENR |= 0x00000805;
    *GPIOA_CRH &= 0xFFFF0000;
    *GPIOA_CRH |= 0x0000BBBB;
    *GPIOB_CRH &= 0x000FFFFF;
    *GPIOB_CRH |= 0xBBB00000;
    *TIM1_ARR = Timperiod;
    *TIM1_CCMR1 = 0x00006868;
    *TIM1_CCMR2 = 0x00006868;
    *TIM1_CCER = 0x00001557;
    *TIM1_PSC = 72;
    *TIM1_BDTR = 0x00008000;
    *TIM1_CR1 = 0x00000061;
    *TIM1_CCR1 = 0x5;
    *TIM1_CCR2 = 0x5;
    *TIM1_CCR3 = 0x5;
    *TIM1_CCR4 = 0x5;
}
void loop()
{
    //Плата:1
    Timperiod = 255;
    PWM_1 = (255)-((map((_gtv2), (0), (4095), (0), (255))));
    PWM_2 = (map((_gtv2), (0), (4095), (0), (128)));
    PWM_3 = (map((_gtv2), (0), (4095), (0), (255)));
    PWM_4 = (map((_gtv2), (0), (4095), (0), (255)));
    *TIM1_ARR = Timperiod;
    PWMcontrol = PWM_1;
    PWMcontrol = constrain(PWM_1,0,Timperiod);
    *TIM1_CCR1 = PWMcontrol;
    PWMcontrol = PWM_2;
    PWMcontrol = constrain(PWM_2,0,Timperiod);
    *TIM1_CCR2 = PWMcontrol;
    PWMcontrol = PWM_3;
    PWMcontrol = constrain(PWM_3,0,Timperiod);
    *TIM1_CCR3 = PWMcontrol;
    PWMcontrol = PWM_4;
    PWMcontrol = constrain(PWM_4,0,Timperiod);
    *TIM1_CCR4 = PWMcontrol;
    // test= *TIM1_CNT;
// Fr=test;
    //   if (test >=PWMcontrol)
     //   {Q=false;}
     //   else 
//    {Q=true;}
    _gtv2 =  (analogRead (197));
}
„Выживает не самый сильный и не самый умный, а тот, кто лучше всех приспосабливается к изменениям.“
— Чарлз Дарвин
Ответить

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