Neo_Matrix 0 14 мая, 2019 Опубликовано 14 мая, 2019 · Жалоба Да, я выше отписал, что внес изменения. Просто сейчас нет с собой последнего кода. По поводу обработки ошибок посмотрите, на скриншот. https://electronix.ru/forum/uploads/monthly_2019_05/image.png.9b928738676a71ba399fd46b3b49b619.png Там есть 2 варианта прерываний на ошибки(EIE, RXNEIE при этом флаг ORE может вызывать прерывание в обоих случаях). Один из них это выключить прерывание по приему и включить прерывания на ошибки, тогда подвиснем в прерывании навечно(до выставления флага RXNE так точно). Потому прерывания ошибок обрабатываю отдельно. Но это не суть. В случае зависания в отладчике эти флаги не выставлены, т.е. не выставлен не один из всех возможных флагов прерываний кроме LBD Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Neo_Matrix 0 14 мая, 2019 Опубликовано 14 мая, 2019 · Жалоба До того, как выше посоветовали внести обработку ошибок, код был где-то таким: void uart_irq_handler(uint32_t uart_number) { uart_data_t *uart_data; volatile uint32_t tmp_reg; uint32_t cr3_reg; uint32_t cr1_reg; uint32_t sr_reg; uint8_t data; uart_data = get_uart_port_data(uart_number); cr1_reg = read_reg(uart_data->uart_typedef, CR1); sr_reg = read_reg(uart_data->uart_typedef, SR); if((read_bit(cr1_reg, USART_CR1_RXNEIE) != (CLEAR))) { if(read_bit(sr_reg, USART_SR_ORE) != (CLEAR)) { tmp_reg = read_reg(uart_data->uart_typedef, SR); // Clear error (void)tmp_reg; tmp_reg = read_reg(uart_data->uart_typedef, DR); (void)tmp_reg; } else { if(read_bit(sr_reg, USART_SR_RXNE) != (CLEAR)) { // Save data data = (uint8_t)(read_bit_reg(uart_data->uart_typedef, DR, USART_DR_DR)); drv_rx_from_isr(uart_data->driver_data, tmp_pdata.data_void); } } } ......................................... } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
VladislavS 39 14 мая, 2019 Опубликовано 14 мая, 2019 · Жалоба Попробуй вот так, больше чем уверен, что ничего виснуть не будет. uint32_t sr = USART1->SR; if((sr & USART_SR_RXNE) && (USART1->CR1 & USART_CR1_RXNEIE)) { uint32_t dr = USART1->SR; if(sr & (USART_SR_PE | USART_SR_FE | USART_SR_NE | USART_SR_ORE)) { //Была ошибка в приеме байта // в dr мусор } else { // в dr нормальные данные } } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Neo_Matrix 0 14 мая, 2019 Опубликовано 14 мая, 2019 (изменено) · Жалоба Попробую, но как-то не уверен, что поможет, не может же быть, что какой-то флаг установлен, а дебагер его не отображает. С флагом ОРЕ должна быть другая обработка, текущий байт ведь в порядке, потерян следующий. Завтра сделаю скрины с дебагера, в случае зависания порта. Изменено 14 мая, 2019 пользователем Neo_Matrix Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Neo_Matrix 0 14 мая, 2019 Опубликовано 14 мая, 2019 (изменено) · Жалоба 18 минут назад, VladislavS сказал: Попробуй вот так, больше чем уверен, что ничего виснуть не будет. В даташите сказано, что последовательное чтение регистров SR - > DR очищает флаг прерывания. У вас между этими чтениями происходит чтение регистра CR1 в условии if. Это точно правильно? Ст. 1009 допустим: Цитата This bit is set by hardware when a parity error occurs in receiver mode. It is cleared by a software sequence (a read from the status register followed by a read or write access to the USART_DR data register). The software must wait for the RXNE flag to be set before clearing the PE bit Изменено 14 мая, 2019 пользователем Neo_Matrix Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
VladislavS 39 14 мая, 2019 Опубликовано 14 мая, 2019 · Жалоба Очистит, никуда он не денется. В любом случае, можно и вынести чтение наружу. Но я бы вообще не выключал прерывания по приёму никогда и отказался от этой проверки. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Neo_Matrix 0 14 мая, 2019 Опубликовано 14 мая, 2019 · Жалоба У меня есть юарты работающие только на прием и только на передачу(точнее такой был раньше). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
VladislavS 39 14 мая, 2019 Опубликовано 14 мая, 2019 · Жалоба Ну значит оставь проверку CR1, ни на что она не влияет. А вот работу с "портом по номеру" стоит переосмыслить. Ну это же правда дичь какая-то. Смотри насколько прощё и читабельнее всё. void uart_irq_handler(USART_TypeDef * pUSART) { if(pUSART->SR & USART_SR_RXNE) { pUSART->DR; } } // void uart_irq_handler(USART_TypeDef * pUSART) // { // if(pUSART->SR & USART_SR_RXNE) LDR R1,[R0, #+0] LSLS R2,R1,#+26 IT MI LDRMI R0,[R0, #+4] // { // pUSART->DR; // } // } BX LR ;; return Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Neo_Matrix 0 14 мая, 2019 Опубликовано 14 мая, 2019 · Жалоба А как переписать универсально под все порты, не применяя номера портов или указатели на структуры? Я выбрал номер и создал массив структур, в которых хранится доп инфа, допустим указатели на буферы РТОСа, а номер передается в качестве индекса массива. Я не нашел других простых подходов. Лично для меня код хорошо читаем, при компиляции с включенной оптимизацией собирается в достаточно компактный вид, другого мне не нужно. Функции на подобие read_bit() это обычные макросы, в которых описано, что и у вас в условии if. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
VladislavS 39 15 мая, 2019 Опубликовано 15 мая, 2019 · Жалоба Дело твоё, но когда я вижу вот это volatile uint32_t tmp_reg; tmp_reg = read_reg(uart_data->uart_typedef, DR); (void)tmp_reg; то возникают большие сомнения в адекватности того что от меня спрятали за макросами и "массивами структур указателей". А вообще, очень хорошо, даже просто замечательно, что это всё не у меня. Заставить виснуть UART не многим удаётся. Мой совет такой - напиши простой работающий на 100% во всех условиях код, а затем его "универсализируй". Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 143 15 мая, 2019 Опубликовано 15 мая, 2019 · Жалоба 9 часов назад, Neo_Matrix сказал: не применяя номера портов или указатели на структуры? Никак. Но предпочтительнее хранить указатель, чтобы избежать постоянного вычисления "номер => указатель". Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 243 15 мая, 2019 Опубликовано 15 мая, 2019 · Жалоба 9 часов назад, Neo_Matrix сказал: А как переписать универсально под все порты, не применяя номера портов или указатели на структуры? Я выбрал номер и создал массив структур, в которых хранится доп инфа, допустим указатели на буферы РТОСа, а номер передается в качестве индекса массива. Я не нашел других простых подходов. Создать структуру, в которой будут храниться все эти указатели, в том числе и указатель на периферийные регистры UART. На каждый порт - своя такая структура. И везде передавать указатель на неё вместо номера порта. У меня так: struct UartHndVar { u16 volatile rposTx, wposTx; //позиции чтения/записи передачи u16 volatile rposRx, wposRx; //позиции чтения/записи приёма u8 volatile waitTx, waitRx; //id ожидающей задачи ОС; если нет такой ==OS_PRIO_SELF }; struct UartHnd { UartHndVar *var; HwRegsUSIC::T_CH volatile *io; char *bufTx, *bufRx; u16 sizTx, sizRx; u8 srFmrTx, srFmrRx; void Init() const; void IsrRx() const; void IsrTx() const; void IsrErr() const; void Timer() const; void Tx(int) const; void Tx(void const *, uint) const; int Rx() const; int Rx(u32, u32) const; int NoEmptyTx() const; int NoEmptyRx() const { int i = var->rposRx; return i - var->wposRx; } }; где: io - указатель на регистры периферии данного UART; далее - все необходимые данные по данному порту для драйвера UART. UartHnd - const и может храниться во флешь. UartHndVar - находится в ОЗУ, содержит текущие изменяющиеся параметры (позиции чтения/записи в FIFO и т.п.). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Neo_Matrix 0 16 мая, 2019 Опубликовано 16 мая, 2019 (изменено) · Жалоба В 15.05.2019 в 07:11, VladislavS сказал: Дело твоё, но когда я вижу вот это volatile uint32_t tmp_reg; tmp_reg = read_reg(uart_data->uart_typedef, DR); (void)tmp_reg; то возникают большие сомнения в адекватности того что от меня спрятали за макросами и "массивами структур указателей". А вообще, очень хорошо, даже просто замечательно, что это всё не у меня. Заставить виснуть UART не многим удаётся. Мой совет такой - напиши простой работающий на 100% во всех условиях код, а затем его "универсализируй". Нечего необычного в этом нет, это стандартный набор макросов из CMSIS, просто маленькими буквами. Неужели не видели? #define read_reg(__INSTANCE__, __REG__) READ_REG(__INSTANCE__->__REG__) #define SET_BIT(REG, BIT) ((REG) |= (BIT)) #define CLEAR_BIT(REG, BIT) ((REG) &= ~(BIT)) #define READ_BIT(REG, BIT) ((REG) & (BIT)) #define CLEAR_REG(REG) ((REG) = (0x0)) #define WRITE_REG(REG, VAL) ((REG) = (VAL)) #define READ_REG(REG) ((REG)) А volatile перед tmp_reg нужен для того что бы оптимизатор не выкинул пустое чтение регистра, которое необходимо для очистки флагов, попробуйте без него и будете потом долго искать почему флаги не сбрасываются, так что меня терзают сомнения, что у вас код намного лучше моего. А вот эта конструкция (void)tmp_reg; необходима для того, что бы анализаторы кода не давали ложных варнингов, потому как переменная нигде не используется. Удается ли добиться многим зависание порта незнаю, возможно просто этому не придают значения. У меня все хорошо работало на многих точках(300+) с закрытыми коннекторами на протяжении почти 2х лет. проблемы возникли только после установки на новое оборудование с коннекторами, которые могут дотронутся своим RX TX до металлического корпуса устройства тем самым посадив линии в ноль. Корпус устройства заземлен и соединен с минусом питания. В 15.05.2019 в 08:34, Сергей Борщ сказал: Никак. Но предпочтительнее хранить указатель, чтобы избежать постоянного вычисления "номер => указатель". Здесь согласен на 100%, но тогда структура должна быть глобальной и видимой во всех файлах, которые ее используют. Так как она используется и в прерывании тоже. Мне наглядней использовать номер порта, как это сделано в стандартном PPP стеке LWIP. Это к сожалению уже личные предпочтения каждого и у всех фломастеры разные на вкус. Изменено 16 мая, 2019 пользователем Neo_Matrix Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Neo_Matrix 0 16 мая, 2019 Опубликовано 16 мая, 2019 · Жалоба В 15.05.2019 в 08:47, jcxz сказал: Создать структуру, в которой будут храниться все эти указатели, в том числе и указатель на периферийные регистры UART. На каждый порт - своя такая структура. И везде передавать указатель на неё вместо номера порта. У меня так: Как и в ответе выше, у всех подход свой и у всех он разный. Мне показалось, что ваша структура содержит слишком много данных, но для вас это в самый раз. Так что здесь каждому свое. Мне вспомнился подобный подход в портах под разные отладочные платы, которые пишет СТМ(не утверждаю что это плохо или хорошо). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 243 16 мая, 2019 Опубликовано 16 мая, 2019 · Жалоба 8 минут назад, Neo_Matrix сказал: Как и в ответе выше, у всех подход свой и у всех он разный. Мне показалось, что ваша структура содержит слишком много данных, но для вас это в самый раз. При чём тут количество данных в ней? Она содержит те данные, которые нужны для работы драйвера. Не больше и не меньше. Если для вашего драйвера нужны другие данные - естественно они будут другие и количество будет другое. И тот мой пост был ответом на ваше сообщение, в котором вы писали, что не смогли найти способа как всё объединить в единое целое (и указатель на периферию UART и указатели на буфера FIFO и т п.) с единым указателем на это. Я продемонстрировал как это сделать. И далее во всех функциях пользоваться только этим указателем, без всяких "номеров порта" и т.п. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться