STM32 новичку в ARM что к чему
- Сообщения: 2567
- Зарегистрирован: Вт май 01, 2018 19:44:47
Да, я перепутал idle с таймаут. Но это не отменяет того что на f103 для решения задачи таймер нужен.
- Реклама
- Сообщения: 362
- Зарегистрирован: Вс апр 03, 2022 07:01:29
А никто и не против таймера. Покажите, кто тут против этого? Но таймер можно выбрать как аппаратный типа TIM4, так и программный таймер на основе SysTicj.
- Сообщения: 2567
- Зарегистрирован: Вт май 01, 2018 19:44:47
ЗЫ: Меня вот в соседней теме лечят, что на третьей планете от солнца никто не ошибается. Врут, поди?
- Сообщения: 362
- Зарегистрирован: Вс апр 03, 2022 07:01:29
Не знаю, я не астроном, в планетах не разбираюсь.
Ошибаются хоть иногда - все. Но не многие умеют признавать свои ошибки и не обсираться от справедливой критики
Ошибаются хоть иногда - все. Но не многие умеют признавать свои ошибки и не обсираться от справедливой критики
- Сообщения: 2516
- Зарегистрирован: Пт июл 12, 2019 22:52:01
Я, кстати, и забыл, что у меня есть уже готовый прием с таймаутами:
Если на предыдущем сообщении был таймаут, следующее даст об этом знать.
Но если сделать на конечных автоматах с проверкой таймаута снаружи, можно будет об этом сразу узнать, как таймаут кончится.
Но такой КА любой дятел может написать, зачем форум загромождать? Вот, например. С такими макросами:
Добавлено after 30 minutes 15 seconds:
Кстати, такой вопрос: какие флаги компилятора/сборщика указывать для того, чтобы на STM32F103 работал sqrt? У меня так:
При попытке вызвать sqrt МК зависает.
Хочу проверить, можно ли F103 использовать для компактного тепловизора. А для каждого из 768 пикселей надо по 4 раза sqrt вызвать, и хрен затабулируешь эту дурную функцию (параметров больше одного) ☹
Добавлено after 10 minutes 19 seconds:
Кстати, внутри sqrtf зачем-то используются double!
Код: Выделить всё
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)Кстати, такой вопрос: какие флаги компилятора/сборщика указывать для того, чтобы на 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)
Хочу проверить, можно ли F103 использовать для компактного тепловизора. А для каждого из 768 пикселей надо по 4 раза sqrt вызвать, и хрен затабулируешь эту дурную функцию (параметров больше одного) ☹
Добавлено after 10 minutes 19 seconds:
Кстати, внутри sqrtf зачем-то используются double!
Linux rules! Windows must die. Здравомыслящий человек добровольно будет пользоваться мастдаем лишь в двух случаях: под дулом автомата или под влиянием анального зонда.
Я на гитхабе, в ЖЖ
Я на гитхабе, в ЖЖ
- Реклама
- Сообщения: 2567
- Зарегистрирован: Вт май 01, 2018 19:44:47
[uquote="Eddy_Em",url="/forum/viewtopic.php?p=4235608#p4235608"]При попытке вызвать sqrt МК зависает.[/uquote]Отладчик, опять не нужен?
Вот этого достаточно должно быть
Вот этого достаточно должно быть
Насчёт double - проверяй, чтобы все литералы были с f.-mcpu=cortex-m3 -mthumb -mfloat-abi=soft
- Сообщения: 2516
- Зарегистрирован: Пт июл 12, 2019 22:52:01
VladislavS, все это есть. А отладчик, естественно, не нужен: чем бы он мне помог здесь?
Похоже, у меня какая-то кривая сборка arm-none-eabi, хотя эту качал с армовского сайта…
С double внутри sqrtf нагуглил, что она действительно просто вызывает обычный sqrt! Поэтому и делает преобразования туда-сюда.
Ладно, датчик я все равно спалил, так что, пока новый из Китая придет, у меня будет минимум месяц ☹
В любом случае, я понимаю, что если тупой обсчет данных (без сложных функций) длится аж пару десятков миллисекунд, если там еще на каждый пиксель по 5 (оказывается, даже 5 надо!) корней будет, оно вообще будет жутко тормозным. Надо мобильный тепловизор на F303 или F401 делать, их есть у меня. А для all-sky камеры я напрямую на I2C "апельсинки" датчики повешу.
Похоже, у меня какая-то кривая сборка arm-none-eabi, хотя эту качал с армовского сайта…
С double внутри sqrtf нагуглил, что она действительно просто вызывает обычный sqrt! Поэтому и делает преобразования туда-сюда.
Ладно, датчик я все равно спалил, так что, пока новый из Китая придет, у меня будет минимум месяц ☹
В любом случае, я понимаю, что если тупой обсчет данных (без сложных функций) длится аж пару десятков миллисекунд, если там еще на каждый пиксель по 5 (оказывается, даже 5 надо!) корней будет, оно вообще будет жутко тормозным. Надо мобильный тепловизор на F303 или F401 делать, их есть у меня. А для all-sky камеры я напрямую на I2C "апельсинки" датчики повешу.
Linux rules! Windows must die. Здравомыслящий человек добровольно будет пользоваться мастдаем лишь в двух случаях: под дулом автомата или под влиянием анального зонда.
Я на гитхабе, в ЖЖ
Я на гитхабе, в ЖЖ
- Сообщения: 1853
- Зарегистрирован: Вт авг 15, 2017 10:51:13
[uquote="Eddy_Em",url="/forum/viewtopic.php?p=4235647#p4235647"]А отладчик, естественно, не нужен: чем бы он мне помог здесь?
...
С double внутри sqrtf нагуглил, что она действительно просто вызывает обычный sqrt![/uquote]И сколько понадобилось потратить часов, чтобы выяснить это?
А с отладчиком это обнаруживается за минуту.
PS: Не удивлюсь если Вы и огонь добываете посредством трения двух палочек, а спички не признаёте.
...
С double внутри sqrtf нагуглил, что она действительно просто вызывает обычный sqrt![/uquote]И сколько понадобилось потратить часов, чтобы выяснить это?
А с отладчиком это обнаруживается за минуту.
PS: Не удивлюсь если Вы и огонь добываете посредством трения двух палочек, а спички не признаёте.
- Сообщения: 2516
- Зарегистрирован: Пт июл 12, 2019 22:52:01
- Сообщения: 362
- Зарегистрирован: Вс апр 03, 2022 07:01:29
- Сообщения: 65
- Зарегистрирован: Ср сен 24, 2014 12:30:09
Что-то я не так делаю, друзья. Та же фигня - бесконечное прыгание из прерывания 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
1. Таймер на какой период настроен?
2. Зачем ждать в прерывании USART_SR_RXNE, если в прерывание попадаем только когда он взведён? Раз других прерываний UART не разрешено, то весь этот while можно заменить просто USART1->SR;
3. Проверки SymbolCount переусложнены. Пока не принят последний символ обнуляем и запускаем, иначе стоп таймер. Всего одно условие.
4. Флаг таймера можно сбрасывать просто записью нуля в SR.
2. Зачем ждать в прерывании USART_SR_RXNE, если в прерывание попадаем только когда он взведён? Раз других прерываний UART не разрешено, то весь этот while можно заменить просто USART1->SR;
3. Проверки SymbolCount переусложнены. Пока не принят последний символ обнуляем и запускаем, иначе стоп таймер. Всего одно условие.
4. Флаг таймера можно сбрасывать просто записью нуля в SR.
- Сообщения: 65
- Зарегистрирован: Ср сен 24, 2014 12:30:09
1. Таймер настроен на 60 миллисекунд.
2. Учту, спасибо!
3. Также учту.
Спасибо за ответ! Но Ваши замечания относятся, скорее, к производительности, чем к причине, почему у меня возникает такая ситуация. Нет никаких домыслов по этому поводу?
2. Учту, спасибо!
3. Также учту.
Спасибо за ответ! Но Ваши замечания относятся, скорее, к производительности, чем к причине, почему у меня возникает такая ситуация. Нет никаких домыслов по этому поводу?
- Сообщения: 2567
- Зарегистрирован: Вт май 01, 2018 19:44:47
Домыслы... Эха с той стороны нет? Так то криминала в коде не видно.
Точно только прерывание по переполнению включено?
Точно только прерывание по переполнению включено?
- Сообщения: 362
- Зарегистрирован: Вс апр 03, 2022 07:01:29
Таймер должен запускаться в режиме ОДНОКРАТНОГО!! счета. One-Pulse Mode. Иначе таймер будет каждые 60 мс срабатывать.
Если вы уже попали в прерывание UART, то не нужно ожидать флага RXNE, поскольку прерывание срабатывает именно по этому флагу. При условии, что вы конечно включили срабатывание по RXNE.
В прерывании нужно проверить флаг RNXE через if, причем вот так:
вторую проверку бита USART_CR1_RXNEIE можно не делать, если не планируется выключать этот запрос прерывания.
А всё остальное не нужно. А в прерывании таймера сбросить флаг этого прерывания и установить программный флаг превышения таймаута, а заодним и сбросить счетчик индекса приемного буфераю
Таймаут, как я понимаю, вы делаете для того, чтобы распознать прекращение передачи извне. Таким образом, срабатывание таймера таймаута будет автоматически разделять пакеты.
В строчке TIM4->SR &=~ TIM_SR_UIF значок & не нужен, потому что сброс бита производится записью в него 0, запись 1 не влияет. Поэтому, инвертированное значение бита TIM_SR_UIF достаточно.
И при однократном режиме таймер в прерывании остановится сам.
Если вы уже попали в прерывание UART, то не нужно ожидать флага RXNE, поскольку прерывание срабатывает именно по этому флагу. При условии, что вы конечно включили срабатывание по RXNE.
В прерывании нужно проверить флаг RNXE через if, причем вот так:
Код: Выделить всё
if((USART1->SR & USART_SR_RNXE) && (USART1->CR1 & USART_CR1_RXNEIE))
{
// прочитать принятый байт из DR в буфер
// перезапустить таймер таймаута
}
А всё остальное не нужно. А в прерывании таймера сбросить флаг этого прерывания и установить программный флаг превышения таймаута, а заодним и сбросить счетчик индекса приемного буфераю
Таймаут, как я понимаю, вы делаете для того, чтобы распознать прекращение передачи извне. Таким образом, срабатывание таймера таймаута будет автоматически разделять пакеты.
В строчке TIM4->SR &=~ TIM_SR_UIF значок & не нужен, потому что сброс бита производится записью в него 0, запись 1 не влияет. Поэтому, инвертированное значение бита TIM_SR_UIF достаточно.
И при однократном режиме таймер в прерывании остановится сам.
Последний раз редактировалось НовыйДень Вт май 24, 2022 22:04:43, всего редактировалось 4 раза.
- Сообщения: 2516
- Зарегистрирован: Пт июл 12, 2019 22:52:01
Полез переделывать USB на STM32F103, который у меня нахрапом (скопировав с F303) не вышел.
Обнаружил интересную фигню: при тех же флагах (за исключением относящихся к архитектуре) CFLAGS и LDFLAGS, F103 вешается на системных функциях (strlen и memcpy). Сделал свою реализацию strlen/memcpy — виснуть перестало! Остается найти, где я нарукожопил в кольцевом буфере, что на больших потоках данных подвисает (а F303 не подвисал — т.е. явно проблема с быстродействием → моим рукожопием).
Обнаружил интересную фигню: при тех же флагах (за исключением относящихся к архитектуре) CFLAGS и LDFLAGS, F103 вешается на системных функциях (strlen и memcpy). Сделал свою реализацию strlen/memcpy — виснуть перестало! Остается найти, где я нарукожопил в кольцевом буфере, что на больших потоках данных подвисает (а F303 не подвисал — т.е. явно проблема с быстродействием → моим рукожопием).
Linux rules! Windows must die. Здравомыслящий человек добровольно будет пользоваться мастдаем лишь в двух случаях: под дулом автомата или под влиянием анального зонда.
Я на гитхабе, в ЖЖ
Я на гитхабе, в ЖЖ
- Сообщения: 65
- Зарегистрирован: Ср сен 24, 2014 12:30:09
[uquote="НовыйДень",url="/forum/viewtopic.php?p=4236055#p4236055"]Таймаут, как я понимаю, вы делаете для того, чтобы распознать прекращение передачи извне. Таким образом, срабатывание таймера таймаута будет автоматически разделять пакеты.[/uquote]
Спасибо за ответ! Вы подали мне несколько идей, где может крыться ошибка. Задача таймаута в моем случае одна: если за отведенное время мы не получили все 10 символов команды, то выдавать ошибку компу. Если же мы получили все 10 символов, таймаут сработать не должен. Завтра доберусь до компа и проверю наши с Вами домыслы.
Спасибо за ответ! Вы подали мне несколько идей, где может крыться ошибка. Задача таймаута в моем случае одна: если за отведенное время мы не получили все 10 символов команды, то выдавать ошибку компу. Если же мы получили все 10 символов, таймаут сработать не должен. Завтра доберусь до компа и проверю наши с Вами домыслы.
- Сообщения: 2567
- Зарегистрирован: Вт май 01, 2018 19:44:47
[uquote="НовыйДень",url="/forum/viewtopic.php?p=4236055#p4236055"][/uquote]Совершенно излишняя проверка, если вы не включаете другие прерывания USART (рассматриваемый случай) или не выключаете RXNE никогда (тоже наш случай). Лучше уж ошибки проверить, это хотя бы полезно.
Lum1noFor, One Pulse не обязательно, вы же его выключаете по срабатыванию. Проблема точно не тут, но с One Pulse можно убрать это выключение, так что, вполне разумно именно с ним.
Код: Выделить всё
if((USART1->SR & USART_SR_RNXE) && (USART1->CR1 & USART_CR1_RXNEIE)) 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
Ув. НовыйДень подал мне идею насильно сбрасывать флаг прерывания USART1 (в данном случае RXNE) в прерывании таймера таймаута. Тогда, возможно, возврата в предыдущее прерывание по стеку не будет. Нужно проверять.
Судя по моим мучениям с этой простейшей штукой, я подозреваю, что здесь что-то не совсем чисто: допустим, прерывание TIM4 сработало посередине выполнения кода прерывания USART1. Тогда, отработав, прерывание TIM4 должно отдать управление прерыванию USART1 В ТО ЖЕ МЕСТО (по стеку), ОТКУДА ОНО СРАБОТАЛО. Это касается главного цикла программы. Но здесь, судя по всему, прерывание USART1 ВСЕГДА начинается сначала, то есть с вектора прерывания. Не с той команды внутри прерывания, с которой оно было прервано, а всегда сначала. Поэтому надо каким-то образом "убрать" из стека это самое прерывание USART1, чтобы оно считалось уже выполненным на момент срабатывания TIM4. А когда сработает TIM4 - знает только сам TIM4
. В общем, попробую.
В ПИКах от Микрочипа можно было просто отключить Nested Interrupts. Почему здесь нельзя - вопрос.
Судя по моим мучениям с этой простейшей штукой, я подозреваю, что здесь что-то не совсем чисто: допустим, прерывание TIM4 сработало посередине выполнения кода прерывания USART1. Тогда, отработав, прерывание TIM4 должно отдать управление прерыванию USART1 В ТО ЖЕ МЕСТО (по стеку), ОТКУДА ОНО СРАБОТАЛО. Это касается главного цикла программы. Но здесь, судя по всему, прерывание USART1 ВСЕГДА начинается сначала, то есть с вектора прерывания. Не с той команды внутри прерывания, с которой оно было прервано, а всегда сначала. Поэтому надо каким-то образом "убрать" из стека это самое прерывание USART1, чтобы оно считалось уже выполненным на момент срабатывания TIM4. А когда сработает TIM4 - знает только сам TIM4
В ПИКах от Микрочипа можно было просто отключить Nested Interrupts. Почему здесь нельзя - вопрос.
- Сообщения: 2567
- Зарегистрирован: Вт май 01, 2018 19:44:47


