Ngu*_*Anh 5 c multithreading stm32 freertos mplab
我已经FreeRTOS
在一些嵌入式项目中使用了一年时间,到目前为止它工作得非常完美。FreeRTOS
目前我面临着一个与使用高速中断移植到相关的难题PIC24H
,希望大家能帮助我解决这个问题。提前致谢
我创建了一个小型演示项目以方便测试:
两个任务:
// Task 1
if (xTaskCreate(RTOSTask_1, (signed char) "[T1]", configMINIMAL_STACK_SIZE2, NULL, tskIDLE_PRIORITY + 1, &hTask1) == errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY)
{
LREP("\r\nCannot create Task 1.");
Display_Error(1000);
}
// Task 2
if (xTaskCreate(RTOSTask_2, (signed char) "[T2]", configMINIMAL_STACK_SIZE2, NULL, tskIDLE_PRIORITY + 2, &hTask2) == errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY)
{
LREP("\r\nCannot create Task 2.");
Display_Error(1000);
}
Run Code Online (Sandbox Code Playgroud)
任务落实:
void RTOSTask_1(void* pvParameter)
{
while(1)
{
if (xSemaphoreTake(hTask1Semaphore, portMAX_DELAY) == pdTRUE)
{
putchar1('1');
}
}
}
void RTOSTask_2(void* pvParameter)
{
while(1)
{
if (xSemaphoreTake(hTask2Semaphore, portMAX_DELAY) == pdTRUE)
{
putchar1('2');
}
}
}
Run Code Online (Sandbox Code Playgroud)
为了让以上两个任务运行,我使用 one Timer
& oneUART
为它们提供信号量:
void attribute((interrupt, auto_psv)) _T2Interrupt (void)
{
_T2IF = 0;
static signed portBASE_TYPE xTaskWoken = pdFALSE;
xSemaphoreGiveFromISR(hTask1Semaphore, &xTaskWoken );
if( xTaskWoken != pdFALSE )
{
taskYIELD();
}
}
void attribute((interrupt, auto_psv)) _U1TXInterrupt()
{
_U1TXIF = 0;
putchar1('E');
}
void attribute((interrupt, auto_psv)) _U1RXInterrupt()
{
_U1RXIF = 0;
if(U1STAbits.URXDA == 1)
{
uint8 u8Recv = U1RXREG;
}
static signed portBASE_TYPE xTaskWoken;
xTaskWoken = pdFALSE;
xSemaphoreGiveFromISR(hTask2Semaphore, &xTaskWoken);
if( xTaskWoken != pdFALSE )
{
taskYIELD();
}
}
Run Code Online (Sandbox Code Playgroud)
我的定时器每 100us 中断一次,UART 工作在 230400 bps 波特率速度。
运行几秒或几分钟后,程序崩溃并跳转到陷阱:
_AddressError
或者
_StackError
我不知道这个问题怎么会发生。经过长时间的调查和测试,我认为当程序在中断服务例程(ISR)中运行和运行时,就会出现问题。看来我们需要几个SAVE_CONTEXT()
&RESTORE_CONTEXT()
函数。但在PIC24端口上没有这样的人。
请您针对这个问题给我一些建议
谢谢你们 !
我想我已经发现了我的问题。当PIC24H进入和退出中断服务程序时,就会出现问题,这里它们是UART RX、TX、定时器中断。
目前我不使用这样的 ISR:
void属性((中断, auto_psv))
相反,我自己用汇编代码创建了一个机制:
__U1RX中断:; 将CPU寄存器压入堆栈
PUSH SR
PUSH W0
PUSH W1
PUSH.D W2
PUSH.D W4
PUSH.D W6
PUSH.D W8
PUSH.D W10
PUSH.D W12
PUSH W14
PUSH RCOUNT
PUSH TBLPAG
PUSH CORCON
PUSH PSVPAG
; Call my ISR
call _UART1_RxISRHandler
; Pop out CPU registers
POP PSVPAG
POP CORCON
POP TBLPAG
POP RCOUNT
POP W14
POP.D W12
POP.D W10
POP.D W8
POP.D W6
POP.D W4
POP.D W2
POP.D W0
POP SR
retfie
Run Code Online (Sandbox Code Playgroud)
UART1_RxISRHandler 是我的 ISR 实现。我对 TX 进行同样的操作,定时器中断。
结果是我的程序运行更流畅,时间更长了1小时(程序崩溃前仅1-5分钟后)。但最后运行1-2小时后仍然崩溃。这意味着我的方法是正确的,但仍然有问题。可能是我错过了上面代码的一些内容。
如果大家对这种情况有什么理想,请告诉我。
谢谢
尝试使用队列。LPC1769 上的示例。您可以轻松地将其移植到您的 MCU 中。
定义 mainQUEUE_LENGTH ( 1 )
这将修复可以存储在队列中的最大字节数。根据您的要求修改它,因此将免受堆栈错误或地址错误的影响:
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
/* Priorities at which the tasks are created. */
#define mainQUEUE_RECEIVE_TASK_PRIORITY ( tskIDLE_PRIORITY + 2 )
#define mainQUEUE_SEND_TASK_PRIORITY ( tskIDLE_PRIORITY + 1 )
/* The bit of port 0 that the LPCXpresso LPC13xx LED is connected. */
#define mainLED_BIT ( 22 )
/* The rate at which data is sent to the queue, specified in milliseconds. */
#define mainQUEUE_SEND_FREQUENCY_MS ( 500 / portTICK_RATE_MS )
/* The number of items the queue can hold. This is 1 as the receive task
will remove items as they are added, meaning the send task should always find
the queue empty. */
#define mainQUEUE_LENGTH ( 1 )
/*
* The tasks as described in the accompanying PDF application note.
*/
static void prvQueueReceiveTask( void *pvParameters );
static void prvQueueSendTask( void *pvParameters );
/*
* Simple function to toggle the LED on the LPCXpresso LPC17xx board.
*/
static void prvToggleLED( void );
/* The queue used by both tasks. */
static xQueueHandle xQueue = NULL;
/*-----------------------------------------------------------*/
int main(void)
{
/* Initialise P0_22 for the LED. */
LPC_PINCON->PINSEL1 &= ( ~( 3 << 12 ) );
LPC_GPIO0->FIODIR |= ( 1 << mainLED_BIT );
/* Create the queue. */
xQueue = xQueueCreate( mainQUEUE_LENGTH, sizeof( unsigned long ) );
if( xQueue != NULL )
{
/* Start the two tasks as described in the accompanying application
note. */
xTaskCreate( prvQueueReceiveTask, ( signed char * ) "Rx", configMINIMAL_STACK_SIZE, NULL, mainQUEUE_RECEIVE_TASK_PRIORITY, NULL );
xTaskCreate( prvQueueSendTask, ( signed char * ) "TX", configMINIMAL_STACK_SIZE, NULL, mainQUEUE_SEND_TASK_PRIORITY, NULL );
/* Start the tasks running. */
vTaskStartScheduler();
}
/* If all is well we will never reach here as the scheduler will now be
running. If we do reach here then it is likely that there was insufficient
heap available for the idle task to be created. */
for( ;; );
}
/*-----------------------------------------------------------*/
static void prvQueueSendTask( void *pvParameters )
{
portTickType xNextWakeTime;
const unsigned long ulValueToSend = 100UL;
/* Initialise xNextWakeTime - this only needs to be done once. */
xNextWakeTime = xTaskGetTickCount();
for( ;; )
{
/* Place this task in the blocked state until it is time to run again.
The block state is specified in ticks, the constant used converts ticks
to ms. While in the blocked state this task will not consume any CPU
time. */
vTaskDelayUntil( &xNextWakeTime, mainQUEUE_SEND_FREQUENCY_MS );
/* Send to the queue - causing the queue receive task to flash its LED.
0 is used as the block time so the sending operation will not block -
it shouldn't need to block as the queue should always be empty at this
point in the code. */
xQueueSend( xQueue, &ulValueToSend, 0 );
}
}
/*-----------------------------------------------------------*/
static void prvQueueReceiveTask( void *pvParameters )
{
unsigned long ulReceivedValue;
for( ;; )
{
/* Wait until something arrives in the queue - this task will block
indefinitely provided INCLUDE_vTaskSuspend is set to 1 in
FreeRTOSConfig.h. */
xQueueReceive( xQueue, &ulReceivedValue, portMAX_DELAY );
/* To get here something must have been received from the queue, but
is it the expected value? If it is, toggle the LED. */
if( ulReceivedValue == 100UL )
{
prvToggleLED();
}
}
}
/*-----------------------------------------------------------*/
static void prvToggleLED( void )
{
unsigned long ulLEDState;
/* Obtain the current P0 state. */
ulLEDState = LPC_GPIO0->FIOPIN;
/* Turn the LED off if it was on, and on if it was off. */
LPC_GPIO0->FIOCLR = ulLEDState & ( 1 << mainLED_BIT );
LPC_GPIO0->FIOSET = ( ( ~ulLEDState ) & ( 1 << mainLED_BIT ) );
}
Run Code Online (Sandbox Code Playgroud)