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

Кто любит RISC в жизни, заходим, не стесняемся.
Ответить
Собутыльник Кота
Аватара пользователя
Сообщения: 2567
Зарегистрирован: Вт май 01, 2018 19:44:47

Сообщение VladislavS »

Да, я перепутал idle с таймаут. Но это не отменяет того что на f103 для решения задачи таймер нужен.
Реклама
Потрогал лапой паяльник
Аватара пользователя
Сообщения: 362
Зарегистрирован: Вс апр 03, 2022 07:01:29

Сообщение НовыйДень »

А никто и не против таймера. Покажите, кто тут против этого? Но таймер можно выбрать как аппаратный типа TIM4, так и программный таймер на основе SysTicj.
Реклама
Собутыльник Кота
Аватара пользователя
Сообщения: 2567
Зарегистрирован: Вт май 01, 2018 19:44:47

Сообщение VladislavS »

ЗЫ: Меня вот в соседней теме лечят, что на третьей планете от солнца никто не ошибается. Врут, поди?
Потрогал лапой паяльник
Аватара пользователя
Сообщения: 362
Зарегистрирован: Вс апр 03, 2022 07:01:29

Сообщение НовыйДень »

Не знаю, я не астроном, в планетах не разбираюсь.
Ошибаются хоть иногда - все. Но не многие умеют признавать свои ошибки и не обсираться от справедливой критики :)
Реклама
Эиком - электронные компоненты и радиодетали
Собутыльник Кота
Аватара пользователя
Сообщения: 2516
Зарегистрирован: Пт июл 12, 2019 22:52:01

Сообщение Eddy_Em »

Я, кстати, и забыл, что у меня есть уже готовый прием с таймаутами:

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

void usart1_isr(){
    static uint32_t tmout = 0;
    if(USART1->SR & USART_SR_RXNE){ // RX not emty - receive next char
        if(tmout && Tms >= tmout){ // set overflow flag
            bufovr = 1;
            idatalen[rbufno] = 0;
        }
        tmout = Tms + TIMEOUT_MS;
        if(!tmout) tmout = 1; // prevent 0
        uint8_t rb = USART1->DR;
        if(idatalen[rbufno] < UARTBUFSZI){ // put next char into buf
            rbuf[rbufno][idatalen[rbufno]++] = rb;
            if(rb == '\n'){ // got newline - line ready
                linerdy = 1;
                dlen = idatalen[rbufno];
                recvdata = rbuf[rbufno];
                // prepare other buffer
                rbufno = !rbufno;
                idatalen[rbufno] = 0;
                // clear timeout at line end
                tmout = 0;
            }
        }else{ // buffer overrun
            bufovr = 1;
            idatalen[rbufno] = 0;
            tmout = 0;
        }
    }
}
Если на предыдущем сообщении был таймаут, следующее даст об этом знать.
Но если сделать на конечных автоматах с проверкой таймаута снаружи, можно будет об этом сразу узнать, как таймаут кончится.
Но такой КА любой дятел может написать, зачем форум загромождать? Вот, например. С такими макросами:

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

#define chstate(s) do{errctr = 0; Tlast = Tms; mlx_state = s;}while(0)
#define chkerr()   do{if(++errctr > MLX_MAXERR_COUNT){chstate(M_ERROR); DBG("-> M_ERROR");}}while(0)
#define chktmout() do{if(Tms - Tlast > MLX_TIMEOUT){chstate(M_ERROR); DBG("Timeout! -> M_ERROR"); }}while(0)
Добавлено after 30 minutes 15 seconds:
Кстати, такой вопрос: какие флаги компилятора/сборщика указывать для того, чтобы на STM32F103 работал sqrt? У меня так:

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

FP_FLAGS    ?= -msoft-float -mfloat-abi=soft
ASM_FLAGS   ?= -mthumb -mcpu=cortex-m3 -mfix-cortex-m3-ldrd
ARCH_FLAGS  = $(ASM_FLAGS) $(FP_FLAGS)
CFLAGS      := -O2 -g -D__thumb2__=1 -MD
CFLAGS      += -Wall -Werror -Wextra -Wshadow
CFLAGS      += -fno-common -ffunction-sections -fdata-sections -fno-stack-protector
CFLAGS      +=  $(ARCH_FLAGS)
LDFLAGS     := -nostartfiles --static -nostdlibs --gc-sections --print-memory-usage
LDFLAGS     += -L$(LIB_DIR) -L$(TOOLCHLIB)
LDFLAGS     += -T$(LDSCRIPT)
LDLIBS      += -lm -lc $(shell $(CC) $(CFLAGS) -print-libgcc-file-name)
...
$(OBJDIR)/%.o: %.c
    @echo "  CC      $<"
    $(CC) $(CFLAGS) $(DEFS) $(INCLUDE) -o $@ -c $<

$(ELF): $(OBJDIR) $(OBJS)
    @echo "  LD      $(ELF)"
    $(LD) $(LDFLAGS) $(OBJS) $(LDLIBS) -o $(ELF)
При попытке вызвать sqrt МК зависает.

Хочу проверить, можно ли F103 использовать для компактного тепловизора. А для каждого из 768 пикселей надо по 4 раза sqrt вызвать, и хрен затабулируешь эту дурную функцию (параметров больше одного) ☹

Добавлено after 10 minutes 19 seconds:
Кстати, внутри sqrtf зачем-то используются double!
Linux rules! Windows must die. Здравомыслящий человек добровольно будет пользоваться мастдаем лишь в двух случаях: под дулом автомата или под влиянием анального зонда.
Я на гитхабе, в ЖЖ
Контактная информация:
Реклама
Собутыльник Кота
Аватара пользователя
Сообщения: 2567
Зарегистрирован: Вт май 01, 2018 19:44:47

Сообщение VladislavS »

[uquote="Eddy_Em",url="/forum/viewtopic.php?p=4235608#p4235608"]При попытке вызвать sqrt МК зависает.[/uquote]Отладчик, опять не нужен?

Вот этого достаточно должно быть
-mcpu=cortex-m3 -mthumb -mfloat-abi=soft
Насчёт double - проверяй, чтобы все литералы были с f.
Реклама
Собутыльник Кота
Аватара пользователя
Сообщения: 2516
Зарегистрирован: Пт июл 12, 2019 22:52:01

Сообщение Eddy_Em »

VladislavS, все это есть. А отладчик, естественно, не нужен: чем бы он мне помог здесь?
Похоже, у меня какая-то кривая сборка arm-none-eabi, хотя эту качал с армовского сайта…
С double внутри sqrtf нагуглил, что она действительно просто вызывает обычный sqrt! Поэтому и делает преобразования туда-сюда.

Ладно, датчик я все равно спалил, так что, пока новый из Китая придет, у меня будет минимум месяц ☹
В любом случае, я понимаю, что если тупой обсчет данных (без сложных функций) длится аж пару десятков миллисекунд, если там еще на каждый пиксель по 5 (оказывается, даже 5 надо!) корней будет, оно вообще будет жутко тормозным. Надо мобильный тепловизор на F303 или F401 делать, их есть у меня. А для all-sky камеры я напрямую на I2C "апельсинки" датчики повешу.
Linux rules! Windows must die. Здравомыслящий человек добровольно будет пользоваться мастдаем лишь в двух случаях: под дулом автомата или под влиянием анального зонда.
Я на гитхабе, в ЖЖ
Контактная информация:
Мудрый кот
Сообщения: 1853
Зарегистрирован: Вт авг 15, 2017 10:51:13

Сообщение jcxz »

[uquote="Eddy_Em",url="/forum/viewtopic.php?p=4235647#p4235647"]А отладчик, естественно, не нужен: чем бы он мне помог здесь?
...
С double внутри sqrtf нагуглил, что она действительно просто вызывает обычный sqrt![/uquote]И сколько понадобилось потратить часов, чтобы выяснить это?
А с отладчиком это обнаруживается за минуту. :beer:

PS: Не удивлюсь если Вы и огонь добываете посредством трения двух палочек, а спички не признаёте. :)
Собутыльник Кота
Аватара пользователя
Сообщения: 2516
Зарегистрирован: Пт июл 12, 2019 22:52:01

Сообщение Eddy_Em »

И сколько понадобилось потратить часов, чтобы выяснить это?
Тупо листинг глянул.
Linux rules! Windows must die. Здравомыслящий человек добровольно будет пользоваться мастдаем лишь в двух случаях: под дулом автомата или под влиянием анального зонда.
Я на гитхабе, в ЖЖ
Контактная информация:
Потрогал лапой паяльник
Аватара пользователя
Сообщения: 362
Зарегистрирован: Вс апр 03, 2022 07:01:29

Сообщение НовыйДень »

А зависание МК тоже по листингу определил? :)))
Открыл глаза
Сообщения: 65
Зарегистрирован: Ср сен 24, 2014 12:30:09

Сообщение Lum1noFor »

Что-то я не так делаю, друзья. Та же фигня - бесконечное прыгание из прерывания USART1 в прерывание TIM4 и обратно. Где я не прав? Код прилагаю. Прерывание TIM4 имеет приоритет 4, прерывание USART1 имеет приоритет 5.

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

volatile uint8_t SymbolCount = 0;
volatile char ReceivedText[20];

void USART1_IRQHandler(void) {

	while (((USART1->SR & USART_SR_RXNE) >> USART_SR_RXNE_Pos) == 0); // Wait for "RX buffer not empty flag".

	ReceivedText[SymbolCount++] = USART1->DR;                                           // Read buffer to ReceivedText[] array.


		if (SymbolCount == 0) {							                 // If first symbol recieved, start "Time out" timer.
			  TIM4->CNT = 0;
			  TIM4->CR1 |= TIM_CR1_CEN;
		}

		if (SymbolCount < 10) {
			TIM4->CNT = 0;												
		} else {
			TIM4->CNT = 0;
			TIM4->CR1 &=~ TIM_CR1_CEN;
			SymbolCount = 0;
		}


}


void TIM4_IRQHandler(void) {

TIM4->SR 	&=~ TIM_SR_UIF		; // Clear TIM4 flag.

TIM4->CR1 	&=~ TIM_CR1_CEN		; // Disable TIM4.

USART_SendStr("Time out!")		;

SymbolCount = 0					; // Set SymbolCount to zero. 

}
Собутыльник Кота
Аватара пользователя
Сообщения: 2567
Зарегистрирован: Вт май 01, 2018 19:44:47

Сообщение VladislavS »

1. Таймер на какой период настроен?
2. Зачем ждать в прерывании USART_SR_RXNE, если в прерывание попадаем только когда он взведён? Раз других прерываний UART не разрешено, то весь этот while можно заменить просто USART1->SR;
3. Проверки SymbolCount переусложнены. Пока не принят последний символ обнуляем и запускаем, иначе стоп таймер. Всего одно условие.
4. Флаг таймера можно сбрасывать просто записью нуля в SR.
Открыл глаза
Сообщения: 65
Зарегистрирован: Ср сен 24, 2014 12:30:09

Сообщение Lum1noFor »

1. Таймер настроен на 60 миллисекунд.
2. Учту, спасибо!
3. Также учту.

Спасибо за ответ! Но Ваши замечания относятся, скорее, к производительности, чем к причине, почему у меня возникает такая ситуация. Нет никаких домыслов по этому поводу?
Собутыльник Кота
Аватара пользователя
Сообщения: 2567
Зарегистрирован: Вт май 01, 2018 19:44:47

Сообщение VladislavS »

Домыслы... Эха с той стороны нет? Так то криминала в коде не видно.

Точно только прерывание по переполнению включено?
Потрогал лапой паяльник
Аватара пользователя
Сообщения: 362
Зарегистрирован: Вс апр 03, 2022 07:01:29

Сообщение НовыйДень »

Таймер должен запускаться в режиме ОДНОКРАТНОГО!! счета. One-Pulse Mode. Иначе таймер будет каждые 60 мс срабатывать.
Если вы уже попали в прерывание UART, то не нужно ожидать флага RXNE, поскольку прерывание срабатывает именно по этому флагу. При условии, что вы конечно включили срабатывание по RXNE.
В прерывании нужно проверить флаг RNXE через if, причем вот так:

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

if((USART1->SR & USART_SR_RNXE) && (USART1->CR1 & USART_CR1_RXNEIE)) 
{ 
    // прочитать принятый байт из DR в буфер
    // перезапустить таймер таймаута
}
вторую проверку бита USART_CR1_RXNEIE можно не делать, если не планируется выключать этот запрос прерывания.
А всё остальное не нужно. А в прерывании таймера сбросить флаг этого прерывания и установить программный флаг превышения таймаута, а заодним и сбросить счетчик индекса приемного буфераю
Таймаут, как я понимаю, вы делаете для того, чтобы распознать прекращение передачи извне. Таким образом, срабатывание таймера таймаута будет автоматически разделять пакеты.

В строчке TIM4->SR &=~ TIM_SR_UIF значок & не нужен, потому что сброс бита производится записью в него 0, запись 1 не влияет. Поэтому, инвертированное значение бита TIM_SR_UIF достаточно.
И при однократном режиме таймер в прерывании остановится сам.
Последний раз редактировалось НовыйДень Вт май 24, 2022 22:04:43, всего редактировалось 4 раза.
Собутыльник Кота
Аватара пользователя
Сообщения: 2516
Зарегистрирован: Пт июл 12, 2019 22:52:01

Сообщение Eddy_Em »

Полез переделывать USB на STM32F103, который у меня нахрапом (скопировав с F303) не вышел.
Обнаружил интересную фигню: при тех же флагах (за исключением относящихся к архитектуре) CFLAGS и LDFLAGS, F103 вешается на системных функциях (strlen и memcpy). Сделал свою реализацию strlen/memcpy — виснуть перестало! Остается найти, где я нарукожопил в кольцевом буфере, что на больших потоках данных подвисает (а F303 не подвисал — т.е. явно проблема с быстродействием → моим рукожопием).
Linux rules! Windows must die. Здравомыслящий человек добровольно будет пользоваться мастдаем лишь в двух случаях: под дулом автомата или под влиянием анального зонда.
Я на гитхабе, в ЖЖ
Контактная информация:
Открыл глаза
Сообщения: 65
Зарегистрирован: Ср сен 24, 2014 12:30:09

Сообщение Lum1noFor »

[uquote="НовыйДень",url="/forum/viewtopic.php?p=4236055#p4236055"]Таймаут, как я понимаю, вы делаете для того, чтобы распознать прекращение передачи извне. Таким образом, срабатывание таймера таймаута будет автоматически разделять пакеты.[/uquote]

Спасибо за ответ! Вы подали мне несколько идей, где может крыться ошибка. Задача таймаута в моем случае одна: если за отведенное время мы не получили все 10 символов команды, то выдавать ошибку компу. Если же мы получили все 10 символов, таймаут сработать не должен. Завтра доберусь до компа и проверю наши с Вами домыслы.
Собутыльник Кота
Аватара пользователя
Сообщения: 2567
Зарегистрирован: Вт май 01, 2018 19:44:47

Сообщение VladislavS »

[uquote="НовыйДень",url="/forum/viewtopic.php?p=4236055#p4236055"]

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

if((USART1->SR & USART_SR_RNXE) && (USART1->CR1 & USART_CR1_RXNEIE)) 
[/uquote]Совершенно излишняя проверка, если вы не включаете другие прерывания USART (рассматриваемый случай) или не выключаете RXNE никогда (тоже наш случай). Лучше уж ошибки проверить, это хотя бы полезно.

Lum1noFor, One Pulse не обязательно, вы же его выключаете по срабатыванию. Проблема точно не тут, но с One Pulse можно убрать это выключение, так что, вполне разумно именно с ним.
СпойлерЯ бы вот так сделал

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

void USART1_IRQHandler(void)
{
  uint32_t sr = USART1->SR;  
  uint8_t data = USART1->DR;    
  if(sr & (USART_SR_PE | USART_SR_FE | USART_SR_NE | USART_SR_ORE))
  {
    // Реакция на ошибку в приеме
  }
  else
  {
    // обработка принятых данных  
  }  
}
Открыл глаза
Сообщения: 65
Зарегистрирован: Ср сен 24, 2014 12:30:09

Сообщение Lum1noFor »

Ув. НовыйДень подал мне идею насильно сбрасывать флаг прерывания USART1 (в данном случае RXNE) в прерывании таймера таймаута. Тогда, возможно, возврата в предыдущее прерывание по стеку не будет. Нужно проверять.

Судя по моим мучениям с этой простейшей штукой, я подозреваю, что здесь что-то не совсем чисто: допустим, прерывание TIM4 сработало посередине выполнения кода прерывания USART1. Тогда, отработав, прерывание TIM4 должно отдать управление прерыванию USART1 В ТО ЖЕ МЕСТО (по стеку), ОТКУДА ОНО СРАБОТАЛО. Это касается главного цикла программы. Но здесь, судя по всему, прерывание USART1 ВСЕГДА начинается сначала, то есть с вектора прерывания. Не с той команды внутри прерывания, с которой оно было прервано, а всегда сначала. Поэтому надо каким-то образом "убрать" из стека это самое прерывание USART1, чтобы оно считалось уже выполненным на момент срабатывания TIM4. А когда сработает TIM4 - знает только сам TIM4 :). В общем, попробую.

В ПИКах от Микрочипа можно было просто отключить Nested Interrupts. Почему здесь нельзя - вопрос.
Собутыльник Кота
Аватара пользователя
Сообщения: 2567
Зарегистрирован: Вт май 01, 2018 19:44:47

Сообщение VladislavS »

Сделать(оставить по умолчанию) приоритет одинаковый.
Ответить

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