Цитата(Kabdim @ Feb 5 2017, 17:12)
Ну что ж начнем сеанс спиритизма и телепатии. Переполненение буфера? Другие длинные обработчики прерываний? Слишком длинный пакет? Где-то бьётся память?
ЗЫ Когда читаешь такой пост с описанием как-то подсознательно ождиаешь увидеть либо минмальный кусок кода на котором воспроизводится баг, либо попытки автора использовать data breakpoints в критичных для его алгоритма местах.
Да,сорри.
Буферы по 2К
Код
// Буфер приема сырых данных:
uint8_t modem_buffer[MODEM_RX_BUFLEN];
__IO uint8_t* modem_buffer_head;
__IO uint8_t* modem_buffer_tail;
// Буфер передачи
uint8_t modem_tx_buffer[MODEM_TX_BUFLEN];
__IO uint8_t* modem_tx_head;
__IO uint8_t* modem_tx_tail;
// Буфер приема сырых данных:
uint8_t pilot_buffer[PILOT_RX_BUFLEN];
__IO uint8_t* pilot_buffer_head;
__IO uint8_t* pilot_buffer_tail;
// Буфер передачи
uint8_t pilot_tx_buffer[PILOT_TX_BUFLEN];
__IO uint8_t* pilot_tx_head;
__IO uint8_t* pilot_tx_tail;
Инициализация портов
Код
HAL_UART_MspInit( &modem_port );
modem_port.Instance = USART2;
modem_port.Init.BaudRate = MODEM_BAUDRATE; // 57600
modem_port.Init.WordLength = UART_WORDLENGTH_8B;
modem_port.Init.StopBits = UART_STOPBITS_1;
modem_port.Init.Parity = UART_PARITY_NONE;
modem_port.Init.Mode = UART_MODE_TX_RX;
modem_port.Init.HwFlowCtl = UART_HWCONTROL_NONE;
modem_port.Init.OverSampling = UART_OVERSAMPLING_16;
if( HAL_UART_Init( &modem_port ) != HAL_OK )
ErrorHandler();
HAL_NVIC_SetPriority( USART2_IRQn, 15, 0 );
HAL_NVIC_EnableIRQ( USART2_IRQn);
HAL_UART_MspInit( &ptm_port );
ptm_port.Instance = USART6;
ptm_port.Init.BaudRate = AP_TM1_BAUDRATE; //1M5
ptm_port.Init.WordLength = UART_WORDLENGTH_8B;
ptm_port.Init.StopBits = UART_STOPBITS_1;
ptm_port.Init.Parity = UART_PARITY_NONE;
ptm_port.Init.Mode = UART_MODE_TX_RX;
ptm_port.Init.HwFlowCtl = UART_HWCONTROL_NONE;
ptm_port.Init.OverSampling = UART_OVERSAMPLING_16;
if( HAL_UART_Init( &ptm_port ) != HAL_OK )
ErrorHandler();
HAL_NVIC_SetPriority( USART6_IRQn, 15, 0 );
HAL_NVIC_EnableIRQ( USART6_IRQn);
Создание задач и очередей
#define MAX_PENDING_PACKETS (32)
#define configMINIMAL_STACK_SIZE ((portBASE_TYPE) 128)
Код
xTaskCreate ( pilotGateKeeper, "p gate", configMINIMAL_STACK_SIZE,
NULL, tskIDLE_PRIORITY + 1, pilotGateKeeperHandle );
xTaskCreate ( modemGateKeeper, "modem gate", configMINIMAL_STACK_SIZE,
NULL, tskIDLE_PRIORITY + 1, modemGateKeeperHandle );
pilotQueue = xQueueCreate ( MAX_PENDING_PACKETS, sizeof(packet_t) );
modemQueue = xQueueCreate ( MAX_PENDING_PACKETS, sizeof(packet_t) );
Гейткиперы почти одинаковы,вот один из них
Код
/*
* Получив сообщение из очереди,берем оттуда адрес начала пакета в сыром буфере,
* его длину, и дописываем в кольцевой буфер передачи порта.Оттуда он будет выдан в
* прерывании передачи
**/
void modemGateKeeper ( void* pvParameters )
{
uint16_t len;
uint16_t idx;
uint8_t* src;
packet_t packet;
// Инициализация буферов
modem_buffer_head = modem_buffer_tail = (uint8_t*)&modem_buffer;
modem_tx_head = modem_tx_tail = (uint8_t*)&modem_tx_buffer;
// Разрешаем прерывания приема символов,передатчик уже включен при инициализации порта
modem_port.Instance->CR1 |= USART_CR1_RXNEIE;
while(1)
{
xQueueReceive ( modemQueue, &packet, portMAX_DELAY );
{
//SEGGER_SYSVIEW_PrintfHost("%d",packet.origin);
//SEGGER_SYSVIEW_PrintfHost("MQ = %d",uxQueueMessagesWaiting(modemQueue) );
len = packet.len;
src = packet.head;
if(packet.origin == PILOT_CHANNEL )
{
for(idx = 0; idx < len;idx++)
{
*modem_tx_tail = *src;
modem_tx_tail++;
if(modem_tx_tail == (uint8_t*)&modem_tx_buffer + MODEM_TX_BUFLEN)
modem_tx_tail = (uint8_t*)&modem_tx_buffer;
src++;
if(src == (uint8_t*)&pilot_buffer + PILOT_RX_BUFLEN )
src = (uint8_t*)&pilot_buffer;
}
// разрешаем передачу
modem_port.Instance->CR1 |= USART_CR1_TXEIE;
}
}
}
Обработчики прерываний - то же
Код
/*
* Обработчик прерываний приема/передачи символов порта модема.
***/
void USART2_IRQHandler(void)
{
uint8_t current_symbol;
packet_t packet;
uint8_t* src;
uint8_t* last_symbol;
uint16_t idx;
uint32_t state = modem_port.Instance->SR;
portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
// Передача символа по указателю на голову буфера
if( ( state & USART_SR_TXE ) && (modem_port.Instance->CR1 & USART_CR1_TXEIE) )
{
modem_port.Instance->DR = *modem_tx_head++;
if(modem_tx_head == (uint8_t*)&modem_tx_buffer + MODEM_TX_BUFLEN )
modem_tx_head = (uint8_t*)&modem_tx_buffer;
if(modem_tx_head == modem_tx_tail)
{
modem_port.Instance->CR1 &= ~USART_CR1_TXEIE;
SEGGER_SYSVIEW_PrintfHost("Mdone");
}
}
/* Указатели на голову и хвост приемника инициализированы на начало буфера при
* старте таска модема
**/
// Прием символа
if( state & USART_SR_RXNE )
{
// Проверка ошибок
if( !( state & ( USART_SR_PE | USART_SR_ORE | USART_SR_NE | USART_SR_FE ) ) )
{
GREEN_LED_TOGGLE;
// принятый символ пишем в буфер
*modem_buffer_tail = modem_port.Instance->DR;
// и отдаем его на анализ
if(parse_char(MODEM_CHANNEL, *modem_buffer_tail,
&message[MODEM_CHANNEL],&status[MODEM_CHANNEL]) )
{
// собран пакет,отдадим его длину в месседж
packet.len = (uint16_t)message[MODEM_CHANNEL].len + MAVLINK_NUM_NON_PAYLOAD_BYTES;
packet.msgid = message[MODEM_CHANNEL].msgid;
packet.origin = MODEM_CHANNEL;
// запомним указатель на последний символ пакета
// и продвинем указатель хвоста на свободное место
last_symbol = modem_buffer_tail++;
if(modem_buffer_tail == (uint8_t*)&modem_buffer + MODEM_RX_BUFLEN)
modem_buffer_tail = (uint8_t*)&modem_buffer;
// найдем указатель на голову
packet.head = ( (last_symbol > modem_buffer_head) ?
(last_symbol - packet.len + 1 ) :
(last_symbol + MODEM_RX_BUFLEN - packet.len + 1 ) );
packet.tail = last_symbol;
modem_buffer_head = modem_buffer_tail;
#ifdef USE_PILOT
xQueueSendToBackFromISR(pilotQueue,&packet,&xHigherPriorityTaskWoken);
#endif
}
// пакет еще не собран,подготовим место для следующего символа
modem_buffer_tail++;
if(modem_buffer_tail == (uint8_t*)&modem_buffer + MODEM_RX_BUFLEN)
modem_buffer_tail = (uint8_t*)&modem_buffer;
}
else
{
char dummy = (char)modem_port.Instance->DR;
}
}
if(xHigherPriorityTaskWoken)
portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
}
В мейне создаются таски и очереди,затем стартует шедулер.
Порт принимает данные,парсит их и отдает гейткиперу другого порта для передачи.
Другой порт делает то же самое,но в другом направлении,пакеты мелкие,2К буфера им с головой хватает,равно как и 32 пакета в очереди
Забыл добавить: использую Eclipse Kepler + arm-none-eabi_5.4_2016q3 + FreeRTOS 9.0.0