Estoy intentando usar el controlador CAN en Kinetis E06 (FRDM-KE06Z). He basado mi código en "FRDM-KEXX Driver Library Package". Para empezar, trato de enviar (y luego recibir) un marco en modo loopback.
Este es mi código de inicialización ( obd_can_init
se llama solo una vez en el inicio, FreeRTOS no tiene nada que ver con esto ya que solo se está ejecutando una tarea):
#include "obd_can.h"
#include <FreeRTOS/include/FreeRTOS.h>
#include <FreeRTOS/include/task.h>
#include <MKE06Z4.h>
#include <string.h>
#if DEFAULT_BUS_CLOCK == 20000000
//Values were calculated using the spreadsheet in dev_documentation directory
#define CANBTR0_500KBAUD 0xC3
#define CANBTR1_500KBAUD 0x34
#define CANBTR0_250KBAUD 0xC7
#define CANBTR1_250KBAUD 0x34
#else
#error "CAN baud registers not defined for this bus clock!"
#endif
#define DEBUG_TERMINAL 0
#include <debug.h>
static void obd_can_transmit(uint32_t identifier, const uint8_t *payload, uint8_t payload_length);
void obd_can_init(void){
portENTER_CRITICAL();
SIM->SCGC |= SIM_SCGC_MSCAN_MASK;
#ifndef BOARD_EVK //EVK uses CAN_TX PTC7 and CAN_RX PTC6, which is the default setting
SIM->PINSEL1 |= SIM_PINSEL1_MSCANPS_MASK; //CAN_TX PTE7, CAN_RX PTH2
#endif
portEXIT_CRITICAL();
MSCAN->CANCTL1 = MSCAN_CANCTL1_CANE_MASK /*enable CAN module*/
| MSCAN_CANCTL1_CLKSRC_MASK /*use bus clock*/;
MSCAN->CANCTL0 |= MSCAN_CANCTL0_INITRQ_MASK; //enter controller initialization mode
while (!(MSCAN->CANCTL1 & MSCAN_CANCTL1_INITAK_MASK)){
//wait for the controller to enter initialization mode
vTaskDelay(2);
}
//set baud
MSCAN->CANBTR0 = CANBTR0_500KBAUD;
MSCAN->CANBTR1 = CANBTR1_500KBAUD;
MSCAN->CANCTL1 |= MSCAN_CANCTL1_LOOPB_MASK; //enable loopback for testing
MSCAN->CANRIER = MSCAN_CANRIER_RXFIE_MASK; //enable RX interrupt
//RX filter
MSCAN->CANIDAR_BANK_1[0] = 0;
MSCAN->CANIDAR_BANK_1[1] = 0;
MSCAN->CANIDAR_BANK_1[2] = 0;
MSCAN->CANIDAR_BANK_1[3] = 0;
//RX filter mask - accept all identifiers
MSCAN->CANIDMR_BANK_1[0] = 0xFF;
MSCAN->CANIDMR_BANK_1[1] = 0xFF;
MSCAN->CANIDMR_BANK_1[2] = 0xFF;
MSCAN->CANIDMR_BANK_1[3] = 0xFF;
MSCAN->CANIDAC = MSCAN_CANIDAC_IDAM(0); //use two 32-bit acceptance filters
MSCAN->CANTIER = MSCAN_CANTIER_TXEIE_MASK; //enable TX interrupt
NVIC_SetPriority(MSCAN_RX_IRQn, 5);
NVIC_EnableIRQ(MSCAN_RX_IRQn);
NVIC_SetPriority(MSCAN_TX_IRQn, 5);
NVIC_EnableIRQ(MSCAN_TX_IRQn);
MSCAN->CANCTL0 &= ~MSCAN_CANCTL0_INITRQ_MASK; //exit initialization mode
while (MSCAN->CANCTL1 & MSCAN_CANCTL1_INITAK_MASK){
//wait for the controller to exit initialization mode
vTaskDelay(2);
}
debugf("OBD CAN initialized");
uint8_t data[] = {1,2,3,4};
obd_can_transmit(10, data, sizeof(data));
obd_can_transmit(10, data, sizeof(data));
obd_can_transmit(10, data, sizeof(data));
}
Este es mi código de transmisión:
static void obd_can_transmit(uint32_t identifier, const uint8_t *payload, uint8_t payload_length){
uint8_t empty_buffer_index = MSCAN->CANTFLG & MSCAN_CANTFLG_TXE_MASK;
if (!(empty_buffer_index)){
debugf("TX busy, dropping frame");
return;
}
debugf("Using buffer %d", empty_buffer_index);
//select transmit buffer
MSCAN->CANTBSEL = MSCAN_CANTBSEL_TX(empty_buffer_index);
uint32_t* identifier_ptr = (uint32_t*)&MSCAN->TEIDR0; //assumes little endianness
*identifier_ptr = identifier;
memcpy((uint8_t*)&MSCAN->TEIDR0, payload, payload_length); //copy payload
MSCAN->TDLR = payload_length;
MSCAN->TBPR = 0; //priority of this buffer
//enable transmission of this buffer
MSCAN->CANTFLG = MSCAN->CANTBSEL & MSCAN_CANTBSEL_TX_MASK;
}
Mi terminal muestra:
9:obd_init: OBD initialization
74:obd_can_init: OBD CAN initialized
88:obd_can_transmit: Using buffer 7
88:obd_can_transmit: Using buffer 6
88:obd_can_transmit: Using buffer 4
Por lo tanto, parece que la transmisión nunca se inicia y el envío de llamadas solo coloca datos en los búferes posteriores. ¿Qué estoy haciendo mal que no active la transmisión?