MCU平台还是S32K146,开发环境是S32DS 用官方的SDK3.0.0,PE配置外设,生成generation code。在SDK上边封装函数,第三库用的ringbuf循环队列,代码实现如下:
hal_uart.c
#include "../inc/hal_uart.h"
extern void LPUART_DRV_StopTxDma(uint32_t instance);
extern void LPUART_DRV_SetIntMode(uint32_t instance, uint32_t intSrc, bool enable);
static void hal_uart_set_hard_flow_ctrl(INT32U instance)
{
hal_uart_hard_flowctrl_reg_t reg = {1, 0, 0, 1, 0};
LPUART_Type* const s_lpuartBase[LPUART_INSTANCE_COUNT] = LPUART_BASE_PTRS;
LPUART_Type* base = s_lpuartBase[instance];
base->MODIR = (base->MODIR & ~LPUART_MODIR_TXCTSE_MASK) | ((reg.TXCTSE ? 1UL : 0UL) << LPUART_MODIR_TXCTSE_SHIFT);
base->MODIR = (base->MODIR & ~LPUART_MODIR_TXRTSE_MASK) | ((reg.TXRTSE ? 1UL : 0UL) << LPUART_MODIR_TXRTSE_SHIFT);
base->MODIR = (base->MODIR & ~LPUART_MODIR_TXRTSPOL_MASK) | ((reg.TXRTSPOL ? 1UL : 0UL) << LPUART_MODIR_TXRTSPOL_SHIFT);
base->MODIR = (base->MODIR & ~LPUART_MODIR_RXRTSE_MASK) | ((reg.RXRTSE ? 1UL : 0UL) << LPUART_MODIR_RXRTSE_SHIFT);
base->MODIR = (base->MODIR & ~LPUART_MODIR_RXRTSE_MASK) | ((reg.RXRTSE ? 1UL : 0UL) << LPUART_MODIR_RXRTSE_SHIFT);
}
static hal_uart_contex_t* hal_uart_get_context(UART_CH_E ch)
{
hal_uart_contex_t* ctx = &g_uart_ctx[ch];
return ctx;
}
static BOOLEAN hal_uart_dcb2conf(uart_dcb_t* dcb, lpuart_user_config_t* conf)
{
switch (dcb->databit)
{
case UART_DATABIT_8:
conf->bitCountPerChar = LPUART_8_BITS_PER_CHAR;
break;
case UART_DATABIT_9:
conf->bitCountPerChar = LPUART_9_BITS_PER_CHAR;
break;
case UART_DATABIT_10:
conf->bitCountPerChar = LPUART_10_BITS_PER_CHAR;
break;
default:
return FALSE;
break;
}
switch (dcb->parity)
{
case UART_PARITY_NONE:
conf->parityMode = LPUART_PARITY_DISABLED;
break;
case UART_PARITY_EVEN:
conf->parityMode = LPUART_PARITY_EVEN;
break;
case UART_PARITY_ODD:
conf->parityMode = LPUART_PARITY_ODD;
break;
default:
return FALSE;
break;
}
switch (dcb->stopbit)
{
case UART_STOPBIT_ONE:
conf->stopBitCount = LPUART_ONE_STOP_BIT;
break;
case UART_STOPBIT_TWO:
conf->stopBitCount = LPUART_TWO_STOP_BIT;
break;
default:
return FALSE;
break;
}
conf->baudRate = dcb->baudrate;
return TRUE;
}
static void hal_uart_free(hal_uart_contex_t* ctx)
{
if (ctx->instance == INST_LPUART1)
{
PINS_DRV_WritePin(PTB, 11, 0);
}
if (ctx->tx_task_hdl)
{
vTaskSuspend(ctx->tx_task_hdl);
vTaskDelete(ctx->tx_task_hdl);
ctx->tx_task_hdl = NULL;
}
if (ctx->rb_rx)
{
ringbuf_free(ctx->rb_rx);
ctx->rb_rx = NULL;
}
if (ctx->rb_tx)
{
ringbuf_free(ctx->rb_tx);
ctx->rb_tx = NULL;
}
if (ctx->bf_rx)
{
vPortFree(ctx->bf_rx);
ctx->bf_rx = NULL;
}
if (ctx->rb_tx_sem)
{
vSemaphoreDelete(ctx->rb_tx_sem);
ctx->rb_tx_sem = NULL;
}
if (ctx->rb_tx_mutex)
{
vSemaphoreDelete(ctx->rb_tx_mutex);
ctx->rb_tx_mutex = NULL;
}
if (ctx->tx_mutex)
{
vSemaphoreDelete(ctx->tx_mutex);
ctx->tx_mutex = NULL;
}
}
static void hal_uart_rx_callback(void* driverState, uart_event_t event, void* userData)
{
(void)driverState;
INT32U remain_bytes = 0;
INT32U recv_bytes = 0;
portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
hal_uart_contex_t* ctx = (hal_uart_contex_t*)userData;
if (event == UART_EVENT_RX_FULL)
{
LPUART_DRV_GetReceiveStatus(ctx->instance, (uint32_t*)&remain_bytes);
if (remain_bytes == ctx->bf_rx_size)
{
recv_bytes = remain_bytes;
}
else
{
recv_bytes = ctx->bf_rx_size - remain_bytes;
}
ctx->hw_recv_bytes += recv_bytes;
ctx->rb_recv_bytes += MIN(ringbuf_free_size(ctx->rb_rx), recv_bytes);
ringbuf_write(ctx->rb_rx, ctx->bf_rx, recv_bytes);
LPUART_DRV_SetRxBuffer(ctx->instance, ctx->bf_rx, ctx->bf_rx_size);
if (xHigherPriorityTaskWoken)
{
portYIELD_FROM_ISR(pdTRUE);
}
}
else if (event == UART_EVENT_ERROR)
{
if (ctx->ch == UART_CH_COMM)
{
}
else
{
LPUART_DRV_StopRxDma(ctx->instance);
LPUART_DRV_ReceiveData(ctx->instance, ctx->bf_rx, ctx->bf_rx_size);
}
}
else
{
}
}
BOOLEAN hal_uart_write(UART_CH_E ch, INT8U* pdata, INT16U len)
{
INT32S left = len;
hal_uart_contex_t* ctx;
if (!(ch < MAX_UART_INDEX && pdata != NULL && len > 0))
{
return FALSE;
}
ctx = hal_uart_get_context(ch);
if (!(ctx != NULL && ctx->rb_tx_mutex != NULL && ctx->rb_tx != NULL && ctx->rb_tx_sem != NULL))
{
return FALSE;
}
xSemaphoreTake(ctx->tx_mutex, 10000);
INT8S retry_cnt = 10;
while (left > 0 && retry_cnt-- > 0)
{
xSemaphoreTake(ctx->rb_tx_mutex, 1000);
if (!ringbuf_is_full(ctx->rb_tx))
{
len = ringbuf_write(ctx->rb_tx, pdata, MIN(ringbuf_free_size(ctx->rb_tx), left));
if (len > 0)
{
left -= len;
pdata += len;
}
xSemaphoreGive(ctx->rb_tx_mutex);
xSemaphoreGive(ctx->rb_tx_sem);
}
else
{
xSemaphoreGive(ctx->rb_tx_mutex);
xSemaphoreGive(ctx->rb_tx_sem);
vTaskDelay(2);
}
}
xSemaphoreGive(ctx->tx_mutex);
if (left > 0)
{
return FALSE;
}
return TRUE;
}
static void hal_uart_tx_task(void* args)
{
hal_uart_contex_t* ctx = (hal_uart_contex_t*)args;
INT32S txsize = 0;
char txbuf[HAL_UART_TX_TASK_STACK_SIZE - 384];
for (;;)
{
if (xSemaphoreTake(ctx->rb_tx_sem, HAL_UART_TX_WAIT_TIMEOUT))
{
xSemaphoreTake(ctx->rb_tx_mutex, 1000);
while (!ringbuf_is_empty(ctx->rb_tx))
{
txsize = ringbuf_read(txbuf, ctx->rb_tx, sizeof(txbuf));
if (txsize > 0)
{
xSemaphoreGive(ctx->rb_tx_mutex);
if (LPUART_DRV_SendDataBlocking(ctx->instance, txbuf, txsize, 100))
{
LPUART_DRV_StopTxDma(ctx->instance);
}
xSemaphoreTake(ctx->rb_tx_mutex, 1000);
}
}
xSemaphoreGive(ctx->rb_tx_mutex);
}
}
}
BOOLEAN hal_uart_open(UART_CH_E ch, uart_dcb_t* dcb)
{
LPUART_Type* s_lpuartBase[LPUART_INSTANCE_COUNT] = LPUART_BASE_PTRS;
hal_uart_contex_t* ctx;
ctx = hal_uart_get_context(ch);
hal_uart_dcb2conf(dcb, ctx->conf);
ctx->ch = ch;
ctx->rb_rx = ringbuf_malloc(dcb->rbuf_size);
ctx->rb_tx_sem = xSemaphoreCreateCounting(255,0);
ctx->rb_tx_mutex = xSemaphoreCreateMutex();
ctx->rb_tx = ringbuf_malloc(dcb->tbuf_size);
ctx->bf_rx = (INT8U*)os_malloc(ctx->bf_rx_size);
ctx->tx_mutex = xSemaphoreCreateMutex();
LPUART_DRV_Init(ctx->instance, ctx->state, ctx->conf);
INT_SYS_DisableIRQGlobal();
LPUART_DRV_SetIntMode(ctx->instance, LPUART_INT_IDLE_LINE, true);
s_lpuartBase[ctx->instance]->CTRL = s_lpuartBase[ctx->instance]->CTRL | 0x0700;
if (dcb->flowctrl == UART_FLOWCTRL_RTSCTS)
{
hal_uart_set_hard_flow_ctrl(ctx->instance);
}
INT_SYS_SetPriority(ctx->irq_num, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY + 1);
if (ctx->instance == INST_LPUART1)
{
INT_SYS_SetPriority(DMA1_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY + 1);
INT_SYS_SetPriority(DMA2_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY + 1);
}
LPUART_DRV_InstallRxCallback(ctx->instance, hal_uart_rx_callback, ctx);
if (ctx->instance == INST_LPUART1)
{
PINS_DRV_WritePin(PTB, 11, 1);
}
INT_SYS_EnableIRQGlobal();
return TRUE;
}
void test_uart(void)
{
const uint8_t sbuf[20] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
for (;;)
{
hal_uart_write(UART_CH_DEBUG, sbuf, sizeof(sbuf));
vTaskDelay(100 / portTICK_RATE_MS);
}
}
hardwaremanage.c
#include "hardwareManage.h"
void hw_uart_open(void)
{
uart_dcb_t hal_dcb;
hal_dcb.rbuf_size = HW_UART_DBG_BUFF_SIZE;
hal_dcb.tbuf_size = HW_UART_DBG_BUFF_SIZE;
hal_uart_open(TO_HW_UART_CH(HW_UART_CH_DEBUG), &hal_dcb);
}
void vSystemHardwareHalInit(void)
{
hw_uart_open();
}
main.c 小灯1S闪烁任务代表系统运行
void vSystemHardwareWorkTask(void *p)
{
while(1)
{
PINS_DRV_TogglePins(PTE,1<<3);
vTaskDelay(1000);
}
}
int main(void)
{
#ifdef PEX_RTOS_INIT
PEX_RTOS_INIT();
#endif
CLOCK_SYS_Init(g_clockManConfigsArr, CLOCK_MANAGER_CONFIG_CNT, g_clockManCallbacksArr, CLOCK_MANAGER_CALLBACK_CNT);
CLOCK_SYS_UpdateConfiguration(0U, CLOCK_MANAGER_POLICY_AGREEMENT);
PINS_DRV_Init(NUM_OF_CONFIGURED_PINS, g_pin_mux_InitConfigArr);
vSystemHardwareHalInit();
xTaskCreate( vSystemHardwareWorkTask, "SystemHardwareWorkTask", 310, 0, 1,0);
vTaskStartScheduler();
}
上边代码的要做的就是打开uart 配置回调函数及创建发送任务,hal_uart_write作为发送API,test_uart测试是否能发送,大概这么个流程。
1. 问题1:程序进入DefaultISR
调试方法1:屏蔽部分代码找到进入硬件中断的问题点。
分析:LPUART_DRV_ReceiveData(ctx->instance, ctx->bf_rx, ctx->bf_rx_size);开启接收函数屏蔽不进入硬件中断,打开进入硬件中断。
调试方法2:论坛的方案
尝试:根据方案描述定义函数DefaultISR,但我的问题是串口实际不能打印,但是仍然重写DefaultISR看一下效果
void DefaultISR(void)
{
#define VECTORNUM (*(volatile uint8_t*)(0xE000ED04))
printf("\n****default_isr entered on vector %d*****\r\n\n", VECTORNUM);
return;
}
效果:工程不卡在DefaultISR中,但是由于是串口初始化导致的DefaultISR,打断点不能看到是哪个中断号出现的问题。换成下边这个
void DefaultISR(void)
{
#define VECTORNUM (*(volatile uint8_t*)(0xE000ED04))
sprintf(buf,"\n****default_isr entered on vector %d %x *****\r\n\n", (uint8_t)VECTORNUM, (uint32_t)VECTORNUM);
return;
}
根据下边这张图定位到vector 3 根据打印出来的数据,判断VECTOR,是怎么原因触发中断的。这里我的值为3,查对应芯片向量表,得知是Hard_Fault导致的。还得接着往下找具体是什么引起的硬件中断。
调试方法3:只要重写函数HardFault_Handler,然后在函数HardFault_Handler里面执行语句“asm(“bx lr”)”可以让程序执行到进入函数HardFault_Handler中断之前的函数,这样是不是就很容易定位到这个地址啦?
void HardFault_Handler(void)
{
__asm("bx lr");
}
问题点好像定位到EDMA_DRV_InstallCallback函数,当通过BL或BLX指令调用子程序时,硬件自动将子程序返回地址保存在R14寄存器中。在子程序返回时,把LR的值复制到程序计数器PC即可实现子程序返回。我在__asm(“bx lr”);打的断点然后单步运行的定位到EDMA_DRV_InstallCallback不知道是不是返回调用处。但是LPUART_DRV_StartReceiveDataUsingDma调用EDMA_DRV_InstallCallback;LPUART_DRV_ReceiveData调用LPUART_DRV_StartReceiveDataUsingDma,这也证实了问题出现在LPUART_DRV_ReceiveData函数。
调试方法4:
uint32_t r0;
uint32_t r1;
uint32_t r2;
uint32_t r3;
uint32_t r12;
uint32_t lr;
uint32_t pc;
uint32_t psr;
void getStackFrame(uint32_t *stackFrame)
{
r0 = stackFrame[0];
r1 = stackFrame[1];
r2 = stackFrame[2];
r3 = stackFrame[3];
r12 = stackFrame[4];
lr = stackFrame[5];
pc = stackFrame[6];
psr = stackFrame[7];
__asm("BKPT");
}
void HardFault_Handler(void)
{
__asm("MOVS R0, #4");
__asm("MOV R1, LR");
__asm("TST R0, R1");
__asm("BEQ _MSP");
__asm("MRS R0, PSP");
__asm("B getStackFrame");
__asm("_MSP:");
__asm("MRS R0, MSP");
__asm("B getStackFrame");
return;
}
得到PC指针为6926 16进制0x1B0E也就是进EDMA_DRV_ConfigSingleBlockTransfer之后发生的硬件故障,本来试图定位代码但是没有找到相关方法。先分析一下这个函数是否有问题。
调试方法5:CmBacktrace(有点麻烦没有用)
解决:是我粗心。。。调用DMA没有初始化DMA,才发生的硬件中断。加上EDMA_DRV_Init(&dmaController1_State,&dmaController1_InitConfig0,edmaChnStateArray,edmaChnConfigArray,EDMA_CONFIGURED_CHANNELS_COUNT);就好了,这一天如同梦游,还是对S32平台不熟悉的缘故。
修改后的源码:
hal_uart.c
BOOLEAN hal_uart_open(UART_CH_E ch, uart_dcb_t* dcb)
{
LPUART_Type* s_lpuartBase[LPUART_INSTANCE_COUNT] = LPUART_BASE_PTRS;
hal_uart_contex_t* ctx;
ctx = hal_uart_get_context(ch);
hal_uart_dcb2conf(dcb, ctx->conf);
ctx->ch = ch;
ctx->rb_rx = ringbuf_malloc(dcb->rbuf_size);
ctx->rb_tx_sem = xSemaphoreCreateCounting(255,0);
ctx->rb_tx_mutex = xSemaphoreCreateMutex();
ctx->rb_tx = ringbuf_malloc(dcb->tbuf_size);
ctx->bf_rx = (INT8U*)os_malloc(ctx->bf_rx_size);
ctx->tx_mutex = xSemaphoreCreateMutex();
LPUART_DRV_Init(ctx->instance, ctx->state, ctx->conf);
INT_SYS_DisableIRQGlobal();
LPUART_DRV_SetIntMode(ctx->instance, LPUART_INT_IDLE_LINE, true);
s_lpuartBase[ctx->instance]->CTRL = s_lpuartBase[ctx->instance]->CTRL | 0x0700;
if (dcb->flowctrl == UART_FLOWCTRL_RTSCTS)
{
hal_uart_set_hard_flow_ctrl(ctx->instance);
}
INT_SYS_SetPriority(ctx->irq_num, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY + 1);
if (ctx->instance == INST_LPUART1)
{
INT_SYS_SetPriority(DMA1_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY + 1);
INT_SYS_SetPriority(DMA2_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY + 1);
}
LPUART_DRV_InstallRxCallback(ctx->instance, hal_uart_rx_callback, ctx);
if (ctx->instance == INST_LPUART1)
{
PINS_DRV_WritePin(PTB, 11, 1);
}
INT_SYS_EnableIRQGlobal();
ctx->tx_task_hdl = xTaskCreate(hal_uart_tx_task,ctx->tx_task_name, HAL_UART_TX_TASK_STACK_SIZE,ctx,HAL_UART_TX_TASK_PRIORITY,NULL) ;
LPUART_DRV_ReceiveData(ctx->instance, ctx->bf_rx, ctx->bf_rx_size);
for (INT8U i = 0; i < sizeof(g_uart_save_status) / sizeof(g_uart_save_status[0]); i++)
{
if (g_uart_save_status[i].ch == ch)
{
g_uart_save_status[i].dcb.baudrate = dcb->baudrate;
g_uart_save_status[i].dcb.databit = dcb->databit;
g_uart_save_status[i].dcb.flowctrl = dcb->flowctrl;
g_uart_save_status[i].dcb.parity = dcb->parity;
g_uart_save_status[i].dcb.rbuf_size = dcb->rbuf_size;
g_uart_save_status[i].dcb.stopbit = dcb->stopbit;
g_uart_save_status[i].dcb.tbuf_size = dcb->tbuf_size;
g_uart_save_status[i].staus = HAL_UART_OPEN;
break;
}
}
return TRUE;
}
增肌hal_board.c
#include "../inc/hal_board.h"
BOOLEAN hal_board_init(void)
{
CLOCK_SYS_Init(g_clockManConfigsArr, CLOCK_MANAGER_CONFIG_CNT, g_clockManCallbacksArr, CLOCK_MANAGER_CALLBACK_CNT);
CLOCK_SYS_UpdateConfiguration(0U, CLOCK_MANAGER_POLICY_AGREEMENT);
PINS_DRV_Init(NUM_OF_CONFIGURED_PINS, g_pin_mux_InitConfigArr);
EDMA_DRV_Init(&dmaController1_State, &dmaController1_InitConfig0, edmaChnStateArray, edmaChnConfigArray, EDMA_CONFIGURED_CHANNELS_COUNT);
}
hardwaremanage.c
#include "hardwareManage.h"
void hw_uart_open(void)
{
uart_dcb_t hal_dcb;
hal_dcb.rbuf_size = HW_UART_DBG_BUFF_SIZE;
hal_dcb.tbuf_size = HW_UART_DBG_BUFF_SIZE;
hal_uart_open(TO_HW_UART_CH(HW_UART_CH_DEBUG), &hal_dcb);
}
void vSystemHardwareHalInit(void)
{
hal_board_init();
hw_uart_open();
}
main.c
void vSystemHardwareWorkTask(void *p)
{
while(1)
{
PINS_DRV_TogglePins(PTE,1<<3);
vTaskDelay(1000);
}
}
int main(void)
{
#ifdef PEX_RTOS_INIT
PEX_RTOS_INIT();
#endif
vSystemHardwareHalInit();
xTaskCreate( vSystemHardwareWorkTask, "SystemHardwareWorkTask", 310, 0, 1,0);
vTaskStartScheduler();
#ifdef PEX_RTOS_START
PEX_RTOS_START();
#endif
for(;;) {
if(exit_code != 0) {
break;
}
}
return exit_code;
}
继续调试!!!!
现象:小灯不闪烁了,但是没有进Hard_Fault,而是卡死在下边的代码里
portFORCE_INLINE static void vPortRaiseBASEPRI( void )
{
uint32_t ulNewBASEPRI;
__asm volatile
(
" mov %0, %1 \n" \
" msr basepri, %0 \n" \
" isb \n" \
" dsb \n" \
:"=r" (ulNewBASEPRI) : "i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY ) : "memory"
);
}
函数vPortRaiseBASEPRI是向寄存器BASEPRI写入宏configMAX_SYSCALL_INTERRUPT_PRIORITY,那么优先级低于configMAX_SYSCALL_INTERRUPT_PRIORITY的中断就会被屏蔽。但是为什么一直卡在这里呢?
照例还是把上边uart任务关闭,看看小灯是否能闪烁,只留一个任务是能运行的,接着两个任务都是小灯闪烁,继续调试。
void vSystemHardwareWorkTask(void *p)
{
while(1)
{
PINS_DRV_TogglePins(PTE,1<<3);
vTaskDelay(1000);
}
}
void vUartDataProcessingTask(void *p)
{
while(1)
{
PINS_DRV_TogglePins(PTE,1<<12);
vTaskDelay(200);
}
}
没有问题,两个灯都能正常闪烁。看这个函数被什么地方调用,放三个全局变量在三个任务里,仿真发现都为0,即都一次没执行就进了vPortRaiseBASEPRI,那应该是在开启调度器时发生的问题。把断点打在vTaskStartScheduler();然后单步仿真,动态申请一个空闲任务进入任务创建;portSTACK_GROWTH进入pvPortMalloc,申请失败返回xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY,应该是内存不够,HAL_UART_TX_TASK_STACK_SIZE我写了1024,太大了?改成300就好了。小等正常闪烁。把其中一个小灯的任务改成调用串口接口发送的任务。
void vUartDataProcessingTask(void *p)
{
const uint8_t sbuf[20] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
while(1)
{
hal_uart_write(UART_CH_DEBUG, sbuf, sizeof(sbuf));
vTaskDelay(500);
count2++;
}
}
效果:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)