реклама на сайте
подробности

 
 
> STM32, USART на прерываниях и очередях, проблемы с передачей, Портится очередь
asdus
сообщение Jan 20 2012, 14:14
Сообщение #1


Участник
*

Группа: Участник
Сообщений: 21
Регистрация: 28-04-08
Из: Раменсбург
Пользователь №: 37 126



Есть проектик, STM32F10*, FreeRTOS 7.1.0
USART реализован на прерываниях и очередях, по примеру из FreeRTOS
С приемом все хорошо, а вот при передаче через некоторое время работы "портятся" данные. Свиду - сдвигаются указатели на голову и хвост в очереди.
В данный момент пройтись отладчиком возможности нет.
Выписал код в минипрогу, ошибка повторяется. Через некоторое, рандомное время, вместо "Hello World!\n" становится, например "rlWorld!\no Wo", потом еще что-нибудь и т.д.
CODE
#include "stm32f10x.h"
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"

static xQueueHandle USART1_TxQueue;

uint8_t USART1_PutChar( uint8_t cOutChar )
{
uint8_t xReturn;

if( xQueueSend( USART1_TxQueue, &cOutChar, 10 ) == pdPASS )
{
xReturn = pdPASS;
USART_ITConfig( USART1, USART_IT_TXE, ENABLE );
}
else
{
xReturn = pdFAIL;
}

return xReturn;
}

void USART1_PutString( const uint8_t * pcString )
{
uint8_t *pxNext;

pxNext = ( uint8_t * ) pcString;
while( *pxNext )
{
USART1_PutChar( *pxNext );
pxNext++;
}
}

void HelloWorldTask(void *pvParameters)
{
for(;;)
{
USART1_PutString("Hello World!\n");
vTaskDelay( 1000 );
}
}

void USART1_IRQHandler( void )
{
portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
uint8_t cChar;

if( USART_GetITStatus( USART1, USART_IT_TXE ) == SET )
{
if( xQueueReceiveFromISR( USART1_TxQueue, &cChar, &xHigherPriorityTaskWoken ) == pdTRUE )
{
USART_SendData( USART1, cChar );
}
else
{
USART_ITConfig( USART1, USART_IT_TXE, DISABLE );
}
}

portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );
}

int main(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;

/* Enable USART1 GPIO clock */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);

/* Enable UART1 clock */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);

/* Enable the USART1 Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = configLIBRARY_LOWEST_INTERRUPT_PRIORITY;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);

/* Configure USART1 Tx as alternate function push-pull */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);

/* Configure USART1 Rx as input floating */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);

/* Configure USART1 parameters 115200 8n1 noHW Tx+Rx*/
USART_InitStructure.USART_BaudRate = 115200;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART1, &USART_InitStructure);
USART_Cmd(USART1, ENABLE);

/* Create TxQueue for USART1 */
USART1_TxQueue = xQueueCreate( 256, ( unsigned portBASE_TYPE ) sizeof( uint8_t ) );

USART1_PutString("Program started!\n");
USART1_PutString("================\n");

xTaskCreate(HelloWorldTask, "HelWor", configMINIMAL_STACK_SIZE, NULL, 2, NULL);

vTaskStartScheduler();

for(;;)
{
}
}


Сообщение отредактировал asdus - Jan 20 2012, 14:16


--------------------
Секс - классная штука. Как ни крути...
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов
diwil
сообщение Jan 27 2012, 07:37
Сообщение #2


Местный
***

Группа: Свой
Сообщений: 366
Регистрация: 5-09-06
Из: Санкт-Петербург
Пользователь №: 20 107



ээээ... как показывает практика - использование очередей в уарте не есть самый лучший способ передачи данных по нескольким причинам
- необходимо распределеить память под очередь
- передача одного байта вызывает большой overhead
- еще какие-то-там-я-и-не-помню.

Более того, несмотря на то, что прерывания при низких скоростях приходят довольно-таки редко, для их обработки, тем не менее, требуется выполнить несколько действий.

В stm32 можно использовать DMA на уарте и это позволяет решить проблему оверхеда. Однако без прерываний никак по-любому, однако они будут случаться только тогда, когда приемный буфер заполнен, или когда передача прекращена. При это в оси будет использоваться только один семафор.

Код для stm32l152 ниже.

Может кому пригодится еще. у меня работает в оч критической задаче.

Код
#include "stm32l1xx.h"
#include "stm32l1xx_rcc.h"


#include "stm32l1xx_tim.h"
#include "stm32l1xx_gpio.h"
#include "stm32l1xx_spi.h"
#include "stm32l1xx_dma.h"
#include "stm32l1xx_usart.h"

#include "misc.h"

#include "FreeRTOS.h"
#include "semphr.h"
#include "task.h"
#include "queue.h"

#define  USART2_RX_BUF_SIZE    128
static char usart2_rx_buffer[USART2_RX_BUF_SIZE];


xSemaphoreHandle xSemaphoreUSART2;

void
usart2_init(void)
{
    USART_InitTypeDef        USART_InitStructure;
    GPIO_InitTypeDef        GPIO_InitStructure;
    NVIC_InitTypeDef        NVIC_InitStructure;
    DMA_InitTypeDef          DMA_InitStructure;

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);

    USART_InitStructure.USART_BaudRate = 57600;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    USART_InitStructure.USART_Parity = USART_Parity_No;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;

    USART_Init(USART2, &USART_InitStructure);

    USART_DMACmd(USART2, USART_DMAReq_Tx | USART_DMAReq_Rx, ENABLE);


  /* Enable USART1 IDLE line interrupts because all others are handeled via DMA */
    USART_ITConfig(USART2, USART_IT_IDLE , ENABLE);

      GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_USART2 );
      GPIO_PinAFConfig(GPIOA, GPIO_PinSource3, GPIO_AF_USART2 );

  /* Configure USART1 Tx, RX (PA.02 PA.03) as alternate function push-pull */
      GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3;
      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_40MHz;
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
      GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
      GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
      GPIO_Init(GPIOA, &GPIO_InitStructure);    


      /* Enable the USART1 Interrupt */
      NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
      NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 12;
      NVIC_InitStructure.NVIC_IRQChannelSubPriority = 12;
      NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
      NVIC_Init(&NVIC_InitStructure);
    
    DMA_DeInit(DMA1_Channel6);
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART2->DR;
    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)usart2_rx_buffer;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
    DMA_InitStructure.DMA_BufferSize = USART2_RX_BUF_SIZE;
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
    DMA_Init(DMA1_Channel6, &DMA_InitStructure);


    USART_DMACmd(USART2, USART_DMAReq_Rx, ENABLE);

      NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel6_IRQn;
      NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 12;
      NVIC_InitStructure.NVIC_IRQChannelSubPriority = 11;
      NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
      NVIC_Init(&NVIC_InitStructure);

    /* Enable interrupts on channel 6 */
    DMA_ITConfig(DMA1_Channel6, DMA_IT_TC, ENABLE);
    DMA_ITConfig(DMA1_Channel6, DMA_IT_HT, ENABLE);

    vSemaphoreCreateBinary( xSemaphoreUSART2 );
    xSemaphoreTake( xSemaphoreUSART2, ( portTickType ) portMAX_DELAY );


    USART_DMACmd(USART2, USART_DMAReq_Tx, ENABLE);

    

    USART2->SR = 0;
    DMA_Cmd(DMA1_Channel6, ENABLE);
      USART_Cmd(USART2, ENABLE);
}



int
usart2_send(void *buffer, int size)
{
    DMA_InitTypeDef          DMA_InitStructure;

       if(size > 65535)
        return -2;

//    if (DMA1_Channel7->CNDTR)
//        return -1;

    while(DMA1_Channel7->CNDTR);

    // now configure transmit line:
    // do not enable interrupts
    DMA_DeInit(DMA1_Channel7);
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART2->DR;
    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)buffer;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
    DMA_InitStructure.DMA_BufferSize = size;
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;

    DMA_Init(DMA1_Channel7, &DMA_InitStructure);
    DMA_Cmd(DMA1_Channel7, ENABLE);    

    return 0;
}

  
void USART2_IRQHandler(void)
{
  portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;    
  int statusreg = USART2->SR;
  char uart_messages;

  uart_messages = 0;


  if(statusreg & (1<<4) )   // IDLE. ONLY this interrupt is enabled!!!
  {
     uart_messages = 3;
     USART2->DR;      // dummy read to clear idle flag

  }
  
  if(uart_messages)
  {      
      xSemaphoreGiveFromISR( xSemaphoreUSART2, &xHigherPriorityTaskWoken );  
  }

  portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
}

void
DMA1_Channel6_IRQHandler(void)
{
    portBASE_TYPE xHigherPriorityTaskWoken;
    
    DMA1->IFCR = 7 << 20;    // clear DMA interrupt flags and continue

    xSemaphoreGiveFromISR( xSemaphoreUSART2, &xHigherPriorityTaskWoken );
    portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
}

static int  rx_read;

int
uart2_get_char(portTickType block_time)
{
    int res;

    while(1)
    {
        if (USART2_RX_BUF_SIZE - DMA1_Channel6->CNDTR != rx_read)
        {
            res = usart2_rx_buffer[rx_read];
            rx_read++;
            if(rx_read == USART2_RX_BUF_SIZE)
                rx_read = 0;
            return res & 0xff;
        }

        if (pdFALSE == xSemaphoreTake( xSemaphoreUSART2, ( portTickType ) block_time ))
            return -1;
    }
            
    return 0;
}
Go to the top of the page
 
+Quote Post



Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 30th July 2025 - 00:54
Рейтинг@Mail.ru


Страница сгенерированна за 0.01408 секунд с 7
ELECTRONIX ©2004-2016