Jump to content

    

Neo_Matrix

Участник
  • Content Count

    99
  • Joined

  • Last visited

Posts posted by Neo_Matrix


  1. 1 час назад, GenaSPB сказал:
    • А в двух словах можно опсисать?
    • А на старой партии процессоров костыль не помешал?

    Сама проблема была описана ранее(в первом посте). Переферийный модуль UART4 вис намертво пока не записать в DR любую инфу. На остальных юартах этой проблемы не наблюдалось.

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

  2. 5 часов назад, VladislavS сказал:

    Термин "индусский код" характеризует не гражданство/национальность программиста, а его квалификацию. И если вы нашли подобные примеры кода в lwip (я его не изучал, врать не буду), то он таки и есть индусский. 

    Я в курсе, что такое "индусский код". Просто стек популярный и достаточно навороченный, при своей нетребовательности к ресурсам(тут конечно все относительно).

    Причина проблемы полностью выяснена. Виной странная партия процов. Как и писал ранее в новой партии устройств данной проблемы нет, потому я просто перекинул процы между 2мя устройствами, глюк перекочевал на другую плату вместе с процом, старая же плата с новым процом заработала нормально. Ревизия процов везде "2". Внешне процессора имеют небольшое отличие, глючные имеют блестящие выводы(похоже на покрытие ПОС), новые имеют более коричневый оттенок выводов(возможно иммерсионное золото, но не уверен).

  3. С тактированием все нормально, уже проверял. Косвенно можно судить о нормальном тактировании по ЮСБ который достаточно критичен к частоте. Задежки чтения флеша тоже правильные. Буду надеяться, что проблема решена. Есть еще вероятность, что в прошлой партии неправильно смонтажили компоненты, допустим керамику вокруг проца. Но выпаивать все и проверять - пока не готов.

  4. Итак проблема решена. Решение оказалось весьма тривиальным, на новой партии устройств были установлены процессора с другой датой выпуска, этого прикола на них не наблюдается. Судя по всему бракованная партия, так как ревизия процессоров совпадает.

  5. В итоге упростил обработчик, написал его на голом доступе к регистрам, по рекомендациям выше. В итоге абсолютно нечего не изменилось. При этом, если тот же код использовать на USART2 - все отлично работает и "подвесить" периферию не получается. Вкрадываются подозрения, что это связано с разными модулями периферии APB2\APB1.

    ПС: А с чего вдруг lwip стал внезапно индусским?

  6. 6 минут назад, VladislavS сказал:

    Мой код, естественно, будет лучше

    Я абсолютно не спорю. Но подобный подход использую не только я, пример:

    image.thumb.png.7983d9991ba475a3673c01110966642c.png

     Так же подобный код можно встретить, кажется, в LWIP. При наличии неиспользуемых переменных.

  7. Вы меня не так поняли. Такой подход как у вас у меня тоже используется в драйвере i2c. Я пытался сказать, что не вижу других способов кроме как использовать указатель на структуру или просто номер. Для меня номер в данном случае был предпочтительнее. Но на самом деле изначальный вопрос несколько иной:acute:

  8. В 15.05.2019 в 08:47, jcxz сказал:

    Создать структуру, в которой будут храниться все эти указатели, в том числе и указатель на периферийные регистры UART. На каждый порт - своя такая структура. И везде передавать указатель на неё вместо номера порта. 

    У меня так: 

    Как и в ответе выше, у всех подход свой и у всех он разный. Мне показалось, что ваша структура содержит слишком много данных, но для вас это в самый раз. Так что здесь каждому свое. Мне вспомнился подобный подход в портах под разные отладочные платы, которые пишет СТМ(не утверждаю что это плохо или хорошо).

  9.  

    В 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. Это к сожалению уже личные предпочтения каждого и у всех фломастеры разные на вкус.

  10. А как переписать универсально под все порты, не применяя номера портов или указатели на структуры? Я выбрал номер и создал массив структур, в которых хранится доп инфа, допустим указатели на буферы РТОСа, а номер передается в качестве индекса массива. Я не нашел других простых подходов. Лично для меня код хорошо читаем, при компиляции с включенной оптимизацией собирается в достаточно компактный вид, другого мне не нужно. Функции на подобие read_bit() это обычные макросы, в которых описано, что и у вас в условии if.

  11. 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

     

  12. Попробую, но как-то не уверен, что поможет, не может же быть, что какой-то флаг установлен, а дебагер его не отображает. С флагом ОРЕ должна быть другая обработка, текущий байт ведь в порядке, потерян следующий.

    Завтра сделаю скрины с дебагера, в случае зависания порта.

  13. До того, как выше посоветовали внести обработку ошибок, код был где-то таким:

    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);
    			}
    		}
    	}
      .........................................
    }

     

  14. Да, я выше отписал, что внес изменения. Просто сейчас нет с собой последнего кода. По поводу обработки ошибок посмотрите, на скриншот.

    https://electronix.ru/forum/uploads/monthly_2019_05/image.png.9b928738676a71ba399fd46b3b49b619.png

    Там есть 2 варианта прерываний на ошибки(EIE, RXNEIE при этом флаг ORE может вызывать прерывание в обоих случаях). Один из них это выключить прерывание по приему и включить прерывания на ошибки, тогда подвиснем в прерывании навечно(до выставления флага RXNE так точно). Потому прерывания ошибок обрабатываю отдельно. Но это не суть. В случае зависания в отладчике эти флаги не выставлены, т.е. не выставлен не один из всех возможных флагов прерываний кроме LBD

  15. Ну и где же регистр SR читается не первым? Имеете ввиду CR1, CR3. Как же без их чтения узнать включено ли прерывание в данный момент по определенному событию? Кроме того DR там и читается только при условии, что RXNE установлен при включенном соответствующем прерывании, в других случаях он читается только для очистки флагов ошибок и об этом явным образом написано в даташите.

  16. DMA не использую, так как скорость 9600, максимальная посылка байтов 100 от силы, в основном по 5-10 байт, периодичность посылок 100мс а то и более. Как видите в ДМА нет резона.

    Вот обработчик прерывания, правда не последней версии. Но глючит в любом из них.(Немного отредактировал пост)

    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 tmp_error = CLEAR;
    	union {
    		uint8_t data_8[2];
    		uint16_t data_16;
    	} tmp_data = {0};
    	union {
    		uint8_t *pdata_8;
    		uint16_t *pdata_16;
    		void *data_void;
    	} tmp_pdata;
    
    	uart_data = get_uart_port_data(uart_number);
    	cr3_reg = read_reg(uart_data->uart_typedef, CR3);
    	cr1_reg = read_reg(uart_data->uart_typedef, CR1);
    	sr_reg = read_reg(uart_data->uart_typedef, SR);
      	if((read_bit(cr1_reg, LL_USART_CR1_PEIE) != (CLEAR)) && \
    		 (read_bit(sr_reg, LL_USART_SR_PE) != (CLEAR))) {
    		tmp_error |= UART_ERROR_PE;
    	}
    	if(read_bit(cr3_reg, LL_USART_CR3_EIE) != (CLEAR)) {
    		if(read_bit(sr_reg, USART_SR_ORE) != (CLEAR)) {
    			tmp_error |= UART_ERROR_ORE;
    		}
    		if(read_bit(sr_reg, LL_USART_SR_FE) != (CLEAR)) {
    			tmp_error |= UART_ERROR_FE;
    		}
    		if(read_bit(sr_reg, LL_USART_SR_NE) != (CLEAR)) {
    			tmp_error |= UART_ERROR_NE;
    		}
    	}
    	if((read_bit(cr1_reg, USART_CR1_RXNEIE) != (CLEAR))) {
    		if(read_bit(sr_reg, USART_SR_ORE) != (CLEAR)) {
    			tmp_error |= UART_ERROR_ORE;
    		}
    		if(read_bit(sr_reg, USART_SR_RXNE) != (CLEAR)) {
    			if(read_bit(cr1_reg, USART_CR1_M) != (CLEAR)) {
    				tmp_data.data_16 = (uint16_t)(read_bit_reg(uart_data->uart_typedef, DR, USART_DR_DR));
    				tmp_pdata.data_void = (void *)&tmp_data.data_16;
    			}
    			else {
    				tmp_data.data_8[1] = (uint8_t)(read_bit_reg(uart_data->uart_typedef, DR, USART_DR_DR));
    				tmp_pdata.data_void = (void *)&tmp_data.data_8;
    			}
    			drv_rx_from_isr(uart_data->driver_data, tmp_pdata.data_void);
    		}
    	}
    	if(tmp_error != CLEAR) {
    		tmp_reg = read_reg(uart_data->uart_typedef, SR);
    		(void)tmp_reg;
    		tmp_reg = read_reg(uart_data->uart_typedef, DR);
    		(void)tmp_reg;
    		//tmp_data.data_8[0] |= tmp_error;
    		drv_err_from_isr(uart_data->driver_data, tmp_error);
    	}
    	if((read_bit(cr1_reg, USART_CR1_TXEIE) != (CLEAR)) && \
    		 (read_bit(sr_reg, USART_SR_TXE) != (CLEAR))) {
    		tmp_pdata.data_void = uart_data->uart_tx_data; 
    		if(read_bit(cr1_reg, USART_CR1_M) != (CLEAR)) {
    			write_reg(uart_data->uart_typedef, DR, (*tmp_pdata.pdata_16 & 0x01FFU));
    			if(--uart_data->uart_tx_data_len == 0U) {
    				clear_bit_reg(uart_data->uart_typedef, CR1, USART_CR1_TXEIE);
    				set_bit_reg(uart_data->uart_typedef, CR1, USART_CR1_TCIE);
    			}
    			else {
    				tmp_pdata.pdata_16++;
    				uart_data->uart_tx_data = tmp_pdata.data_void;
    			}
    		}
    		else {
    			write_reg(uart_data->uart_typedef, DR, (*tmp_pdata.pdata_8 & 0xFFU));
    			if(--uart_data->uart_tx_data_len == 0U) {
    				clear_bit_reg(uart_data->uart_typedef, CR1, USART_CR1_TXEIE);
    				set_bit_reg(uart_data->uart_typedef, CR1, USART_CR1_TCIE);
    			}
    			else {
    				tmp_pdata.pdata_8++;
    				uart_data->uart_tx_data = tmp_pdata.data_void;
    			}
    		}
    		//return;
    	}
    	if((read_bit(cr1_reg, LL_USART_CR1_TCIE) != (CLEAR)) && \
    		 (read_bit(sr_reg, LL_USART_SR_TC) != (CLEAR))) {
    		clear_bit_reg(uart_data->uart_typedef, SR, USART_SR_TC);
    		clear_bit_reg(uart_data->uart_typedef, CR1, USART_CR1_TCIE);
    		drv_tx_from_isr(uart_data->driver_data);
    		//return;
    	}
    }

     

  17. Уезжал на праздники, потому долго не отвечал.

    В 28.04.2019 в 11:19, vlad_new сказал:

    Ну во первых флаг LBD - это не обязательно LIN. Например я его использую как флаг начала пакета. 

    Во вторых странно, что у вас не выставляется флаг FE. Хотя он не на что и не влияет. 

    В третьих флаг OVR заслуживает отдельного внимания, поскольку ( как я понял в некоторых камнях ) он блокирует дальнейший приём. В мэнуале как то странно написано, что сбросить его можно чтением приемника ??? и/или ??? чтением регистра SR (вроде). Поэтому при приёме байта сначала вычитываем RX и SR в каие нибудь переменные, а потом уже занимаемся всем остальным. Правда во время обработки приема байта, флаг OVR опять может установиться ( от разного там дребезга в контактах ). Ситуация редкая, но я уже с этим сталкивался (приёмник просто намертво виснет, хотя казалось бы, что ранее флаг OVR был сброшен).

    Вообщем написав уже с не один десяток разных обработчиков пакетов, везде вылезало что то своё и до всего приходилось докапываться самому.

    Ну, LBD у меня при нормальном приеме данных не выставляется(если кабель не дергать на горячую), или я не замечал. FE точно не выставляется, прикрепил скриншот к сообщению, там написано, что этот флаг работает только в мультибуферном режиме . А что за флаг OVR, не нашел такого?

    Спойлер

    image.thumb.png.9229d8ed2ecdef57723902b11551f979.png

    В 28.04.2019 в 12:19, dsl2640free сказал:

    У меня так тоже было. помогла специальная инициализация:

    Не смог найти нечего специального, ткните носом плиз.

     

     

  18. 25 минут назад, ivan24190 сказал:

    А может стоит проверять флаги ошибок приема (FE, NF и т.д.) и сбрасывать их? Т.к. в некоторых случаях прием может "затыкаться" если эти флаги установлены.

    ORE - проверяю, на остальные прерывания отключены. В дебагере четко видно, что ни один из флагов(FE и т.д.) в момент зависания приема - не выставлен, кроме того, как объяснить продолжение нормальной работы после записи в регистр DR(чтение этого регистра проблему не убирает!)

  19. Просмотрел еррату, есть похожая ошибка, но она проявляет себя только при аппаратном контроле потока, который у меня выключен. В итоге непонятно.

    Цитата

    2.7.7 Break request can prevent the Transmission Complete flag (TC) from being set Description

    After the end of transmission of a data (D1), the Transmission Complete (TC) flag will not be set if the following conditions are met:

    CTS hardware flow control is enabled.

    D1 is being transmitted.

    A break transfer is requested before the end of D1 transfer.

    nCTS is de-asserted before the end of D1 data transfer.

    Workaround

    If the application needs to detect the end of a data transfer, the break request should be issued after checking that the TC flag is set.

     

  20. Столкнулся со странным поведение периферии UART4(на других не замечено), а точнее подвисанием. Итак имеется 2 устройства одно из них мое второе третьей стороны, оба устройства подключены по RS232. С моей стороны стоит процессор STM32F407 за ним MAX3232(питание от 3.3вольта) с сапрессорами с другой стороны находится такая же MAX3232 с сапрессорами далее уходит на проц(не смотрел какой). Так вот недалекий обслуживающий персонал частенько вынимает коннектор RS232 "на горячую", поскольку мое устройство питается от блока питания стороннего устройства земли(GND) у них в этот момент не разрываются, но конструкция разъема такова, что при попадании на металлический корпус коннектора RX, TX могут на него замкнуть(от этого защищают резисторы и сапрессоры).

    Теперь суть проблемы: В момент отключения кабеля посылка данных приходящих ко мне может быть принята не полностью, на что мой софт отвечает NACK(0x15), по непонятной мне причине в этот момент может выставится флаг LBD, который используется если настроить порт как LIN, но я не использую этот самый LIN и он не активен и прерываний от него нет, именно в такие моменты периферия подвисает. Если потом вернуть разъем на место, то прерывания RXNE, TXE более не срабатывают, а софт моей задачи вылетает по таймауту.

    В начале попробовал сбрасывать сам флаг LBD - флаг нормально сбрасывается но передача не возобновляется. Нашел 2 способа решить проблему костылем:

    1) Сбросить ЮАРТ периферию и заново перенастроить.

    2) При появлении флага LBD в регистре DR содержится(в случае зависания всегда) значение 0x0015(Мой ответ NACK). Если произвести запись в регистр любых данных все начинает снова работать, даже не нужно сбрасывать LBD. LBD - продолжаю сбрасывать для того что бы хоть как то отследить повторение зависания.

    Еще раз повторюсь функционал LIN Не используется мной, а отслеживание флага LBD сделано для работы костыля. Так же повторюсь, что прерывания после такой ситуации именно перестают срабатывать, а не ПО подвисает в прерывании.

     

    Использую следующую инициализацию порта:

    	LL_USART_DisableRTSHWFlowCtrl(UART4);
    	LL_USART_DisableCTSHWFlowCtrl(UART4);
    	LL_USART_DisableLIN(UART4);
    	LL_USART_DisableSCLKOutput(UART4);
    	LL_USART_DisableSmartcard(UART4);
    	LL_USART_DisableIrda(UART4);
    	LL_USART_DisableHalfDuplex(UART4);
    	LL_USART_SetTransferDirection(UART4, LL_USART_DIRECTION_TX_RX);
    	LL_USART_SetParity(UART4, LL_USART_PARITY_NONE);
    	LL_USART_SetDataWidth(UART4, LL_USART_DATAWIDTH_8B);
    	LL_USART_SetStopBitsLength(UART4, LL_USART_STOPBITS_1);
    	LL_USART_SetOverSampling(UART4, LL_USART_OVERSAMPLING_16);
    	LL_USART_SetBaudRate(UART4, RCC_GetPCLK1ClockFreq(RCC_GetHCLKClockFreq(RCC_GetSystemClockFreq())), LL_USART_OVERSAMPLING_16, baudrate);
    	LL_USART_Enable(UART4);
    	LL_USART_EnableIT_RXNE(UART4);

     

    Может кто то сталкивался с такой ситуацией? Так как 2 вышеописанных метода решения это "костыли" чистой воды, прошу помочь проблему более правильно.