From 01010e72728a979b0a991576d1101d19829ecec5 Mon Sep 17 00:00:00 2001 From: Dominik Sliwa Date: Tue, 11 Sep 2018 15:37:36 +0200 Subject: Improved CAN, locking and general IRQ performance Fixes issues with CAN stopping when overwhelmed by data RX\TX. Keeps can in freezemode until explicitly activated. CANINTF_TX is now a CAN TX in progress flag. Runtime asserts are now disabled. Signed-off-by: Dominik Sliwa --- source/can_task.c | 168 +++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 115 insertions(+), 53 deletions(-) (limited to 'source/can_task.c') diff --git a/source/can_task.c b/source/can_task.c index bab19ac..e34d35d 100644 --- a/source/can_task.c +++ b/source/can_task.c @@ -14,19 +14,13 @@ #define CAN_HEADER_MAX_LEN 5 #define CAN_TRANSFER_BUF_LEN (CAN_HEADER_MAX_LEN + CAN_FRAME_MAX_LEN) -#define CAN_CTRLMODE_NORMAL 0x00 /* normal mode */ -#define CAN_CTRLMODE_LOOPBACK 0x01 /* Loopback mode */ -#define CAN_CTRLMODE_LISTENONLY 0x02 /* Listen-only mode */ -#define CAN_CTRLMODE_3_SAMPLES 0x04 /* Triple sampling mode */ -#define CAN_CTRLMODE_ONE_SHOT 0x08 /* One-Shot mode */ -#define CAN_CTRLMODE_BERR_REPORTING 0x10 /* Bus-error reporting */ - -#define CANCTRL_MODMASK 0x03 -#define CANCTRL_INTMASK 0x38 -#define CANCTRL_INTEN BIT(2) -#define CANINTF_RX BIT(3) -#define CANINTF_TX BIT(4) -#define CANINTF_ERR BIT(5) +#define CANCTRL_MODMASK (BIT(1) | BIT(0)) +#define CANCTRL_INTEN BIT(2) +#define CANINTF_RX BIT(3) +#define CANINTF_TX BIT(4) +#define CANINTF_ERR BIT(5) +#define CANCTRL_ENABLE BIT(6) +#define CANCTRL_INTMASK (CANINTF_RX | CANINTF_TX | CANINTF_ERR) #define EFLG_EWARN 0x01 #define EFLG_RXWAR 0x02 @@ -39,24 +33,26 @@ struct can_registers { CAN_Type *base; flexcan_handle_t handle; - uint8_t can_status_reg; + uint8_t can_enable; uint8_t can_err_reg; uint8_t can_mode; uint8_t frames_in_buf; uint8_t rx_buf_top; uint8_t rx_buf_bottom; + uint8_t tx_counter; }; static uint8_t data_buffer[2][CAN_RX_BUF_SIZE][CAN_TRANSFER_BUF_LEN]; static struct can_registers can_regs[2]; -static void generate_can_irq(uint8_t id) +static inline void generate_can_irq(uint8_t id) { - if (id == 0) + if (id == 0) { GPIO_TogglePinsOutput(GPIOB, 1u << 8u); - else + } else { GPIO_TogglePinsOutput(GPIOE, 1u << 26u); + } } void can_tx_notify_task(void *pvParameters) @@ -66,17 +62,25 @@ void can_tx_notify_task(void *pvParameters) while(1){ xTaskNotifyWait( 0x00, 0xFFFFFFFF, &ulInterruptStatus, portMAX_DELAY); if (ulInterruptStatus & 0x01) { - registers[APALIS_TK1_K20_CANREG + APALIS_TK1_K20_CAN_DEV_OFFSET(0)] |= CANINTF_TX; + registers[APALIS_TK1_K20_CANREG + APALIS_TK1_K20_CAN_DEV_OFFSET(0)] &= ~CANINTF_TX; generate_can_irq(0); } if (ulInterruptStatus & 0x02) { - registers[APALIS_TK1_K20_CANREG + APALIS_TK1_K20_CAN_DEV_OFFSET(1)] |= CANINTF_TX; + registers[APALIS_TK1_K20_CANREG + APALIS_TK1_K20_CAN_DEV_OFFSET(1)] &= ~CANINTF_TX; + generate_can_irq(1); + } + if (ulInterruptStatus & 0x04) { + registers[APALIS_TK1_K20_CANREG + APALIS_TK1_K20_CAN_DEV_OFFSET(0)] |= CANINTF_ERR; + generate_can_irq(0); + } + if (ulInterruptStatus & 0x08) { + registers[APALIS_TK1_K20_CANREG + APALIS_TK1_K20_CAN_DEV_OFFSET(1)] |= CANINTF_ERR; generate_can_irq(1); } } } -static void flexcan_callback(CAN_Type *base, flexcan_handle_t *handle, status_t status, uint32_t result, void *userData) +static BaseType_t flexcan_callback(CAN_Type *base, flexcan_handle_t *handle, status_t status, uint32_t result, void *userData) { callback_message_t * cb = (callback_message_t*) userData; BaseType_t reschedule = pdFALSE; @@ -94,6 +98,7 @@ static void flexcan_callback(CAN_Type *base, flexcan_handle_t *handle, status_t switch ((int)base) { case (int)CAN0: + xTaskNotifyFromISR(can_tx_notify_task_handle, 0x01, eSetBits, &reschedule); break; case (int)CAN1: @@ -104,10 +109,40 @@ static void flexcan_callback(CAN_Type *base, flexcan_handle_t *handle, status_t } break; + case kStatus_FLEXCAN_ErrorStatus: + if ((result & (kFLEXCAN_TxWarningIntFlag)) != 0) { + switch ((int)base) + { + case (int)CAN0: + registers[APALIS_TK1_K20_CANERR + APALIS_TK1_K20_CAN_DEV_OFFSET(0)] |= EFLG_TXWAR; + xTaskNotifyFromISR(can_tx_notify_task_handle, 0x04, eSetBits, &reschedule); + break; + case (int)CAN1: + registers[APALIS_TK1_K20_CANERR + APALIS_TK1_K20_CAN_DEV_OFFSET(1)] |= EFLG_TXWAR; + xTaskNotifyFromISR(can_tx_notify_task_handle, 0x08, eSetBits, &reschedule); + break; + } + } + + if ((result & (kFLEXCAN_BusOffIntFlag)) != 0) { + switch ((int)base) + { + case (int)CAN0: + registers[APALIS_TK1_K20_CANERR + APALIS_TK1_K20_CAN_DEV_OFFSET(0)] |= EFLG_TXBO; + xTaskNotifyFromISR(can_tx_notify_task_handle, 0x04, eSetBits, &reschedule); + break; + case (int)CAN1: + registers[APALIS_TK1_K20_CANERR + APALIS_TK1_K20_CAN_DEV_OFFSET(1)] |= EFLG_TXBO; + xTaskNotifyFromISR(can_tx_notify_task_handle, 0x08, eSetBits, &reschedule); + break; + } + } + break; default: break; } - portYIELD_FROM_ISR(reschedule); + + return reschedule; } static void CAN_Init(uint8_t id) @@ -139,7 +174,11 @@ static void CAN_Init(uint8_t id) FLEXCAN_SetRxFifoConfig(can_regs[id].base, &fifoConfig, true); /* errata #5641 */ - FLEXCAN_SetTxMbConfig(can_regs[id].base, TX_MESSAGE_BUFFER_NUM0 - 1, true); + can_regs[id].base->MB[TX_MESSAGE_BUFFER_NUM0 - 1].ID = 0x0; + can_regs[id].base->MB[TX_MESSAGE_BUFFER_NUM0 - 1].WORD0 = 0x0; + can_regs[id].base->MB[TX_MESSAGE_BUFFER_NUM0 - 1].WORD1 = 0x0; + can_regs[id].base->MB[TX_MESSAGE_BUFFER_NUM0 - 1].CS = CAN_CS_CODE(0x8); + can_regs[id].base->MB[TX_MESSAGE_BUFFER_NUM0 - 1].CS = CAN_CS_CODE(0x8); /* Setup Tx Message Buffer. */ FLEXCAN_SetTxMbConfig(can_regs[id].base, TX_MESSAGE_BUFFER_NUM0, true); @@ -148,6 +187,7 @@ static void CAN_Init(uint8_t id) uint8_t available_data[2]; static void can_calculate_available_data(uint8_t id) { + taskENTER_CRITICAL(); if ( can_regs[id].rx_buf_bottom <= can_regs[id].rx_buf_top) available_data[id] = can_regs[id].rx_buf_top - can_regs[id].rx_buf_bottom; else @@ -155,13 +195,17 @@ static void can_calculate_available_data(uint8_t id) { available_data[id] = (available_data[id] > APALIS_TK1_MAX_CAN_DMA_XREF) ? APALIS_TK1_MAX_CAN_DMA_XREF:available_data[id]; registers[APALIS_TK1_K20_CAN_IN_BUF_CNT + APALIS_TK1_K20_CAN_DEV_OFFSET(id)] = available_data[id]; + if (can_regs[id].rx_buf_bottom == can_regs[id].rx_buf_top) registers[APALIS_TK1_K20_CANREG + APALIS_TK1_K20_CAN_DEV_OFFSET(id)] &= ~CANINTF_RX; + else + registers[APALIS_TK1_K20_CANREG + APALIS_TK1_K20_CAN_DEV_OFFSET(id)] |= CANINTF_RX; + taskEXIT_CRITICAL(); } void can_spi_read_complete(uint8_t id) { - + can_calculate_available_data(id); } static void frame_to_buffer(flexcan_frame_t *frame, uint8_t id) { @@ -195,24 +239,26 @@ static void frame_to_buffer(flexcan_frame_t *frame, uint8_t id) { case 2:data_buffer[id][top_frame][5 + 1] = frame->dataByte1; case 1:data_buffer[id][top_frame][5] = frame->dataByte0; } + can_regs[id].rx_buf_top++; can_regs[id].rx_buf_top %= CAN_RX_BUF_SIZE; + can_calculate_available_data(id); } -static void can_fifo_rx(uint8_t id, flexcan_fifo_transfer_t * rxXfer) +static inline void can_fifo_rx(uint8_t id, flexcan_fifo_transfer_t * rxXfer) { callback_message_t *can_msg = (callback_message_t *) can_regs[id].handle.userData; - taskENTER_CRITICAL(); + FLEXCAN_TransferReceiveFifoNonBlocking(can_regs[id].base, &can_regs[id].handle, rxXfer); - taskEXIT_CRITICAL(); xSemaphoreTake(can_msg->sem, portMAX_DELAY); - frame_to_buffer(rxXfer->frame, id); - can_regs[id].frames_in_buf++; - registers[APALIS_TK1_K20_CANREG + APALIS_TK1_K20_CAN_DEV_OFFSET(id)] |= CANINTF_RX; - generate_can_irq(id); - if (can_regs[id].frames_in_buf >= CAN_RX_BUF_SIZE) - vTaskSuspend(NULL); + if (can_msg->async_status == pdTRUE) { + frame_to_buffer(rxXfer->frame, id); + can_regs[id].frames_in_buf++; + generate_can_irq(id); + if (can_regs[id].frames_in_buf >= CAN_RX_BUF_SIZE) + vTaskSuspend(NULL); + } } void can0_task(void *pvParameters) { @@ -263,16 +309,25 @@ void can1_task(void *pvParameters) { static void can_change_mode(int id, uint8_t new_mode) { - CAN_Type *base = id ? CAN1:CAN0; - can_regs[id].can_mode = new_mode; - switch (new_mode){ - case CAN_CTRLMODE_LOOPBACK: - base->CTRL1 = base->CTRL1 | CAN_CTRL1_LPB_MASK; - break; - case CAN_CTRLMODE_NORMAL: - base->CTRL1 = base->CTRL1 & ~CAN_CTRL1_LPB_MASK; + FLEXCAN_SetMode(can_regs[id].base, new_mode); + +} + +static void can_enable(int id, uint8_t enable) +{ + can_regs[id].can_mode = enable; + + if (enable) { + callback_message_t *can_msg = (callback_message_t *) can_regs[id].handle.userData; + FLEXCAN_ExitFreezeMode(can_regs[id].base); + can_msg->async_status = pdFALSE; + xSemaphoreGive(can_msg->sem); + generate_can_irq(id); + } else { + FLEXCAN_TransferAbortReceiveFifo(can_regs[id].base, &can_regs[id].handle); + FLEXCAN_EnterFreezeMode(can_regs[id].base); } } @@ -282,18 +337,21 @@ static uint8_t set_canreg (int id, uint8_t value) registers[APALIS_TK1_K20_CANREG + APALIS_TK1_K20_CAN_DEV_OFFSET(id)] = value; if ( can_regs[id].can_mode != (value & CANCTRL_MODMASK) ) can_change_mode(id, (value & CANCTRL_MODMASK)); + if (can_regs[id].can_enable != (value & CANCTRL_ENABLE)) + can_enable(id, (value & CANCTRL_ENABLE)); return 0; } static uint8_t clr_canreg (int id, uint8_t mask) { - mask &= (CANINTF_TX | CANINTF_ERR); + mask &= (CANINTF_RX | CANINTF_TX | CANINTF_ERR); registers[APALIS_TK1_K20_CANREG + APALIS_TK1_K20_CAN_DEV_OFFSET(id)] &= ~mask; return 0; } static uint8_t set_canerr (int id, uint8_t value) { + registers[APALIS_TK1_K20_CANERR + APALIS_TK1_K20_CAN_DEV_OFFSET(id)] = value; return 0; } @@ -304,9 +362,9 @@ static uint8_t set_canbadreg (int id, uint8_t value) return 0; } -static uint8_t set_canbittimig (int id, uint16_t value, int16_t mask) +static uint8_t set_canbittiming (int id, uint16_t value, int16_t mask) { - /* According to NXP we should use default setting */ + /* According to NXP we should use default settings */ return 0; } @@ -339,12 +397,16 @@ uint8_t can_sendframe(uint8_t id, uint8_t *data, uint8_t len) txXfer.frame = &tx_frame; txXfer.mbIdx = TX_MESSAGE_BUFFER_NUM0; - - taskENTER_CRITICAL(); - FLEXCAN_TransferSendNonBlocking(can_regs[id].base , &can_regs[id].handle, &txXfer); - taskEXIT_CRITICAL(); - - return 0; + if( tx_frame.length <= 8 ) { + FLEXCAN_TransferSendNonBlocking(can_regs[id].base , &can_regs[id].handle, &txXfer); + registers[APALIS_TK1_K20_CANREG + APALIS_TK1_K20_CAN_DEV_OFFSET(id)] |= CANINTF_TX; + return 0; + } + else { + registers[APALIS_TK1_K20_CANREG + APALIS_TK1_K20_CAN_DEV_OFFSET(id)] &= ~CANINTF_TX; + generate_can_irq(id); + return -EIO; + } } uint16_t can_readframe(uint8_t id, dspi_transfer_t *spi_transfer) @@ -354,11 +416,11 @@ uint16_t can_readframe(uint8_t id, dspi_transfer_t *spi_transfer) rx_size = spi_transfer->rxData[2] / CAN_TRANSFER_BUF_LEN; /* size in frames, not bytes */ if (rx_size > available_data[id]) rx_size = available_data[id]; + can_regs[id].rx_buf_bottom = can_regs[id].rx_buf_bottom + rx_size; can_regs[id].rx_buf_bottom %= CAN_RX_BUF_SIZE; can_regs[id].frames_in_buf -= rx_size; - can_calculate_available_data(id); return rx_size * CAN_TRANSFER_BUF_LEN; } @@ -378,9 +440,9 @@ int canx_registers(dspi_transfer_t *spi_transfer, int id) case APALIS_TK1_K20_CAN_BAUD_REG: return set_canbadreg(id, rx_buf[2]); case APALIS_TK1_K20_CAN_BIT_1: - return set_canbittimig(id, rx_buf[2], 0x00FF); + return set_canbittiming(id, rx_buf[2], 0x00FF); case APALIS_TK1_K20_CAN_BIT_2: - return set_canbittimig(id, (rx_buf[2] << 8), 0xFF00); + return set_canbittiming(id, (rx_buf[2] << 8), 0xFF00); default: return -EIO; } @@ -398,7 +460,7 @@ int canx_registers(dspi_transfer_t *spi_transfer, int id) switch (rx_buf[1]) { case APALIS_TK1_K20_CAN_OUT_BUF: can_sendframe(id, &rx_buf[3], rx_buf[2]); - break; + return 0; default: return -EIO; } -- cgit v1.2.3