Este artigo apresenta uma implementação completa de comunicação via CAN Bus para o processador TMS320F28335, incluindo inicialização do módulo CAN, configuração de múltiplos buffers de comunicação, gerenciamento de interrupções para transmissão e receção, tratamento de erros e suporte ao protocolo CANopen.
Características do Módulo eCAN TMS320F28335
| Característica | Descrição |
|---|---|
| Número de buffers | 32 buffers (16 TX, 16 RX) |
| Taxa de transmissão | Até 1Mbps |
| Protocolo | CAN 2.0B (quadros padrão e estendidos) |
| Tipo de buffer | Configurável como TX ou RX |
| Interrupções | Interrupções de receção/transmissão/erro |
| Filtragem | Registros de máscara de receção |
Configuração recomendada:
- Taxa de transmissão: 500kbps
- Número de buffers: 8 para transmissão, 8 para receção
- Modo de interrupção: Interrupção por buffer de receção
- Clock: 30MHz (clock do sistema 60MHz, com divisão)
Conexão de Hardware
Pinagem do DSP28335 para CAN:
GPIO30 → CANRXA
GPIO31 → CANTXA
Circuito externo:
DSP CAN → Transceptor CAN(TJA1050) → Barramento CAN
↓ ↓
3.3V Alimentação 5V
Importante: É obrigatório o uso de transceptor, pois o CAN do opera em nível TTL e necessita conversão para sinal diferencial.
Arquitetura do Programa
Biblioteca_CAN/
├── can_driver.c # Driver principal do CAN
├── can_driver.h # Arquivo de cabeçalho
├── can_config.c # Funções de configuração
├── can_isr.c # Rotinas de interrupção
└── can_app.c # Exemplo de implementação
Cabeçalho do Driver CAN
// can_driver.h
#ifndef CAN_DRIVER_H
#define CAN_DRIVER_H
#include "DSP2833x_Device.h"
#include "DSP2833x_Examples.h"
// Número de buffers do CAN
#define CAN_BUFFER_COUNT 32
#define CAN_TX_BUFFER_START 16
#define CAN_RX_BUFFER_START 0
// Estados do CAN
typedef enum {
CAN_STATE_UNINIT = 0,
CAN_STATE_READY,
CAN_STATE_BUS_OFF,
CAN_STATE_ERROR
} CAN_State_t;
// Direção do buffer
typedef enum {
CAN_BUFFER_DIR_RX = 0,
CAN_BUFFER_DIR_TX
} CAN_BufferDir_t;
// Tipo de quadro
typedef enum {
CAN_FRAME_STD = 0, // Quadro padrão
CAN_FRAME_EXT // Quadro estendido
} CAN_FrameType_t;
// Configuração do buffer de receção
typedef struct {
Uint16 buffer_num; // Número do buffer 0-31
Uint32 message_id; // ID da mensagem
CAN_FrameType_t frame_type; // Tipo de quadro
Uint16 mask; // Máscara de aceitação
Uint16 data_len; // Comprimento dos dados
} CAN_RxBufferConfig_t;
// Configuração do buffer de transmissão
typedef struct {
Uint16 buffer_num; // Número do buffer 0-31
Uint32 message_id; // ID da mensagem
CAN_FrameType_t frame_type; // Tipo de quadro
Uint16 data_len; // Comprimento dos dados
Uint16 priority; // Prioridade de transmissão
} CAN_TxBufferConfig_t;
// Estrutura de mensagem recebida
typedef struct {
Uint32 message_id; // ID da mensagem
CAN_FrameType_t frame_type; // Tipo de quadro
Uint16 data_len; // Comprimento dos dados
Uint8 data[8]; // Dados
Uint16 timestamp; // Carimbo de tempo
Uint16 buffer_num; // Número do buffer
} CAN_RxMessage_t;
// Estrutura de mensagem para transmissão
typedef struct {
Uint32 message_id; // ID da mensagem
CAN_FrameType_t frame_type; // Tipo de quadro
Uint16 data_len; // Comprimento dos dados
Uint8 data[8]; // Dados
Uint16 buffer_num; // Número do buffer
} CAN_TxMessage_t;
// Contadores de erro
typedef struct {
Uint16 rx_error_count;
Uint16 tx_error_count;
Uint16 bus_off_count;
Uint16 error_passive_count;
} CAN_ErrorCount_t;
// Handle do CAN
typedef struct {
CAN_State_t state;
CAN_ErrorCount_t error_count;
Uint16 baud_rate; // Taxa de transmissão em kbps
Uint16 interrupt_mask; // Máscara de interrupções
void (*rx_callback)(CAN_RxMessage_t* msg); // Callback de receção
void (*error_callback)(Uint16 error_code); // Callback de erro
} CAN_Handle_t;
// Declaração de funções
void CAN_Init(Uint16 baud_rate);
void CAN_ConfigBuffer(CAN_BufferDir_t dir, Uint16 buffer_num,
Uint32 msg_id, CAN_FrameType_t frame_type);
Uint16 CAN_SendData(Uint16 buffer_num, Uint8* data, Uint16 len);
Uint16 CAN_ReceiveData(Uint16 buffer_num, CAN_RxMessage_t* msg);
void CAN_SetRxCallback(void (*callback)(CAN_RxMessage_t*));
void CAN_EnableInterrupt(Uint16 buffer_num, Uint16 enable);
void CAN_ErrorHandler(void);
Uint16 CAN_GetStatus(void);
void CAN_BusOffRecovery(void);
// Funções de configuração de taxa
void CAN_SetBaudRate(Uint16 baud_rate);
// Rotina de serviço de interrupção
interrupt void CAN_ISR(void);
#endif
Inicialização e Configuração do CAN
// can_config.c
#include "can_driver.h"
// Handle global do CAN
CAN_Handle_t can_handle = {0};
// Função de inicialização do CAN
void CAN_Init(Uint16 baud_rate)
{
// 1. Habilitar clock do eCAN
EALLOW;
SysCtrlRegs.PCLKCR0.bit.ECANAENCLK = 1; // Habilitar clock do eCAN-A
EDIS;
// 2. Configurar GPIO para função CAN
EALLOW;
GpioCtrlRegs.GPAMUX2.bit.GPIO30 = 3; // CANRXA
GpioCtrlRegs.GPAMUX2.bit.GPIO31 = 3; // CANTXA
EDIS;
// 3. Inicializar registradores de controle do CAN
// Entrar no modo de inicialização
ECanaRegs.CANMC.bit.CCR = 1; // Solicitar mudança de configuração
while(ECanaRegs.CANES.bit.CCE != 1) {} // Aguardar habilitação de configuração
// 4. Configurar parâmetros de temporização
CAN_SetBaudRate(baud_rate);
// 5. Configurar registradores de máscara de receção
// Máscara de receção global
ECanaMboxes.MBOX0.MSGID.all = 0x00000000; // Sem máscara
// 6. Sair do modo de inicialização
ECanaRegs.CANMC.bit.CCR = 0;
while(ECanaRegs.CANES.bit.CCE != 0) {} // Aguardar desabilitação de configuração
// 7. Inicializar buffers
CAN_InitBuffers();
// 8. Inicializar interrupções
CAN_InitInterrupts();
can_handle.state = CAN_STATE_READY;
can_handle.baud_rate = baud_rate;
}
// Configuração da taxa de transmissão
void CAN_SetBaudRate(Uint16 baud_rate)
{
Uint16 brp, tseg1, tseg2, sjw;
// Clock do sistema = 150MHz (supondo SYSCLKOUT=150MHz)
// Clock do CAN = SYSCLKOUT / (BRP + 1)
// Taxa de transmissão = Clock do CAN / ((TSEG1 + TSEG2 + 1) * (BRP + 1))
switch(baud_rate) {
case 1000: // 1Mbps
brp = 14; // 150/(15)=10MHz
tseg1 = 5; // 5+1=6
tseg2 = 2; // 2+1=3
sjw = 1;
break;
case 500: // 500kbps
brp = 29; // 150/(30)=5MHz
tseg1 = 5; // 5+1=6
tseg2 = 2; // 2+1=3
sjw = 1;
break;
case 250: // 250kbps
brp = 59; // 150/(60)=2.5MHz
tseg1 = 5; // 5+1=6
tseg2 = 2; // 2+1=3
sjw = 1;
break;
case 125: // 125kbps
brp = 119; // 150/(120)=1.25MHz
tseg1 = 5; // 5+1=6
tseg2 = 2; // 2+1=3
sjw = 1;
break;
default: // 500kbps
brp = 29;
tseg1 = 5;
tseg2 = 2;
sjw = 1;
}
// Configurar registrador de temporização
ECanaRegs.CANBTC.bit.BRP = brp;
ECanaRegs.CANBTC.bit.TSEG1 = tseg1;
ECanaRegs.CANBTC.bit.TSEG2 = tseg2;
ECanaRegs.CANBTC.bit.SJW = sjw;
}
// Inicialização dos buffers
void CAN_InitBuffers(void)
{
Uint16 i;
// 1. Inicializar todos os buffers
for(i = 0; i < CAN_BUFFER_COUNT; i++) {
// Limpar registrador de controle do buffer
ECanaMboxes.MBOX[i].MSGCTRL.all = 0x00000000;
// Limpar ID da mensagem
ECanaMboxes.MBOX[i].MSGID.all = 0x00000000;
// Limpar dados
ECanaMboxes.MBOX[i].MDL.all = 0x00000000;
ECanaMboxes.MBOX[i].MDH.all = 0x00000000;
// Configurar como buffer de receção por padrão
if(i < CAN_TX_BUFFER_START) {
// Buffer de receção
ECanaRegs.CANME.all &= ~(1 << i); // Desabilitar buffer
ECanaRegs.CANMD.all &= ~(1 << i); // Configurar como receção
} else {
// Buffer de transmissão
ECanaRegs.CANME.all &= ~(1 << i); // Desabilitar buffer
ECanaRegs.CANMD.all |= (1 << i); // Configurar como transmissão
}
}
// 2. Configurar registrador de direção (CANMD)
// Buffers 0-15: Buffers de receção
// Buffers 16-31: Buffers de transmissão
ECanaRegs.CANMD.all = 0xFFFF0000;
// 3. Habilitar buffers
ECanaRegs.CANME.all = 0x00000000; // Desabilitar todos os buffers inicialmente
// 4. Configurar máscara de receção
// Usar registradores de máscara 0-2
ECanaRegs.CANLAM0.all = 0xFFFFFFFF; // Receção global
ECanaRegs.CANLAM1.all = 0xFFFFFFFF;
ECanaRegs.CANLAM2.all = 0xFFFFFFFF;
}
// Configuração de buffer individual
void CAN_ConfigBuffer(CAN_BufferDir_t dir, Uint16 buffer_num,
Uint32 msg_id, CAN_FrameType_t frame_type)
{
if(buffer_num >= CAN_BUFFER_COUNT) return;
// 1. Desabilitar buffer
ECanaRegs.CANME.all &= ~(1 << buffer_num);
// 2. Definir direção do buffer
if(dir == CAN_BUFFER_DIR_RX) {
ECanaRegs.CANMD.all &= ~(1 << buffer_num); // Receção
} else {
ECanaRegs.CANMD.all |= (1 << buffer_num); // Transmissão
}
// 3. Configurar ID da mensagem
if(frame_type == CAN_FRAME_STD) {
// Quadro padrão
ECanaMboxes.MBOX[buffer_num].MSGID.all = msg_id & 0x7FF; // 11 bits de ID
ECanaMboxes.MBOX[buffer_num].MSGID.bit.IDE = 0; // Quadro padrão
} else {
// Quadro estendido
ECanaMboxes.MBOX[buffer_num].MSGID.all = msg_id & 0x1FFFFFFF; // 29 bits de ID
ECanaMboxes.MBOX[buffer_num].MSGID.bit.IDE = 1; // Quadro estendido
}
// 4. Habilitar buffer
ECanaRegs.CANME.all |= (1 << buffer_num);
}
// Configuração do callback de receção
void CAN_SetRxCallback(void (*callback)(CAN_RxMessage_t*))
{
can_handle.rx_callback = callback;
}
Funções de Transmissão e Receção do CAN
// can_driver.c
#include "can_driver.h"
// Função de envio de mensagem
Uint16 CAN_SendData(Uint16 buffer_num, Uint8* data, Uint16 len)
{
Uint32* pData = (Uint32*)data;
if(buffer_num < CAN_TX_BUFFER_START || buffer_num >= CAN_BUFFER_COUNT) {
return 0; // Número de buffer inválido
}
if(len > 8) len = 8; // CAN suporta no máximo 8 bytes
// 1. Aguardar buffer pronto
if(ECanaRegs.CANTRS.all & (1 << buffer_num)) {
// Buffer ocupado, aguardar liberação
while(ECanaRegs.CANTRS.all & (1 << buffer_num)) {}
}
// 2. Definir comprimento dos dados
ECanaMboxes.MBOX[buffer_num].MSGCTRL.bit.DLC = len;
// 3. Escrever dados
if(len > 0) {
ECanaMboxes.MBOX[buffer_num].MDL.all = pData[0];
}
if(len > 4) {
ECanaMboxes.MBOX[buffer_num].MDH.all = pData[1];
}
// 4. Disparar transmissão
ECanaRegs.CANTRS.all = (1 << buffer_num);
// 5. Aguardar confirmação de transmissão
Uint32 timeout = 10000; // Contador de timeout
while((ECanaRegs.CANTA.all & (1 << buffer_num)) == 0) {
timeout--;
if(timeout == 0) {
can_handle.error_count.tx_error_count++;
return 0; // Timeout na transmissão
}
}
// 6. Limpar flag de confirmação
ECanaRegs.CANTA.all = (1 << buffer_num);
return len;
}
// Função de receção (modo polling)
Uint16 CAN_ReceiveData(Uint16 buffer_num, CAN_RxMessage_t* msg)
{
if(buffer_num >= CAN_TX_BUFFER_START) {
return 0; // Não é buffer de receção
}
// 1. Verificar se há nova mensagem
if((ECanaRegs.CANRMP.all & (1 << buffer_num)) == 0) {
return 0; // Sem nova mensagem
}
// 2. Ler ID da mensagem
if(ECanaMboxes.MBOX[buffer_num].MSGID.bit.IDE) {
// Quadro estendido
msg->frame_type = CAN_FRAME_EXT;
msg->message_id = ECanaMboxes.MBOX[buffer_num].MSGID.all & 0x1FFFFFFF;
} else {
// Quadro padrão
msg->frame_type = CAN_FRAME_STD;
msg->message_id = ECanaMboxes.MBOX[buffer_num].MSGID.bit.STDMSGID;
}
// 3. Ler comprimento dos dados
msg->data_len = ECanaMboxes.MBOX[buffer_num].MSGCTRL.bit.DLC;
// 4. Ler dados
Uint32* pData = (Uint32*)msg->data;
pData[0] = ECanaMboxes.MBOX[buffer_num].MDL.all;
pData[1] = ECanaMboxes.MBOX[buffer_num].MDH.all;
// 5. Limpar flag de receção
ECanaRegs.CANRMP.all = (1 << buffer_num);
// 6. Registrar número do buffer e timestamp
msg->buffer_num = buffer_num;
msg->timestamp = ECanaRegs.CANTSC.all; // Contador de timestamp
return msg->data_len;
}
// Envio de quadro estendido
Uint16 CAN_SendExtFrame(Uint32 id, Uint8* data, Uint16 len, Uint16 buffer_num)
{
if(buffer_num < 16) buffer_num = 16; // Usar buffer de transmissão
// Configurar como quadro estendido
ECanaMboxes.MBOX[buffer_num].MSGID.all = id & 0x1FFFFFFF;
ECanaMboxes.MBOX[buffer_num].MSGID.bit.IDE = 1; // Quadro estendido
ECanaMboxes.MBOX[buffer_num].MSGID.bit.AME = 0; // Sem máscara de receção
return CAN_SendData(buffer_num, data, len);
}
// Envio de quadro padrão
Uint16 CAN_SendStdFrame(Uint16 id, Uint8* data, Uint16 len, Uint16 buffer_num)
{
if(buffer_num < 16) buffer_num = 16; // Usar buffer de transmissão
// Configurar como quadro padrão
ECanaMboxes.MBOX[buffer_num].MSGID.bit.STDMSGID = id & 0x7FF;
ECanaMboxes.MBOX[buffer_num].MSGID.bit.IDE = 0; // Quadro padrão
ECanaMboxes.MBOX[buffer_num].MSGID.bit.AME = 0; // Sem máscara de receção
return CAN_SendData(buffer_num, data, len);
}
Configuração de Interrupções do CAN
// can_isr.c
#include "can_driver.h"
// Tabela de vetores de interrupção
#define CAN_ISR_VECTOR INT14 // Vetor de interrupção CAN-A
// Rotina de serviço de interrupção
interrupt void CAN_ISR(void)
{
Uint16 int_flag;
CAN_RxMessage_t rx_msg;
// 1. Ler flags de interrupção
int_flag = ECanaRegs.CANGIF0.all;
// 2. Interrupção de buffer
if(int_flag & 0x00000001) { // Interrupção de buffer 0-15
// Verificar qual buffer gerou a interrupção
for(int i = 0; i < 16; i++) {
if(ECanaRegs.CANRMP.all & (1 << i)) {
// Ler mensagem
CAN_ReceiveData(i, &rx_msg);
// Chamar callback
if(can_handle.rx_callback != NULL) {
can_handle.rx_callback(&rx_msg);
}
// Limpar flag de interrupção
ECanaRegs.CANRMP.all = (1 << i);
}
}
}
// 3. Interrupção de transmissão concluída
if(int_flag & 0x00000002) { // Interrupção de transmissão
// Limpar flag de confirmação
ECanaRegs.CANTA.all = ECanaRegs.CANTA.all;
}
// 4. Interrupção de erro
if(int_flag & 0x00000004) { // Interrupção de erro
CAN_ErrorHandler();
}
// 5. Interrupção de wake-up
if(int_flag & 0x00000008) { // Interrupção de wake-up
// Wake-up do barramento
ECanaRegs.CANGIF0.bit.WUIF = 0; // Limpar flag
}
// 6. Interrupção de bus-off
if(int_flag & 0x00000010) { // Bus-off
can_handle.state = CAN_STATE_BUS_OFF;
can_handle.error_count.bus_off_count++;
if(can_handle.error_callback != NULL) {
can_handle.error_callback(0x10);
}
ECanaRegs.CANGIF0.bit.BOIF = 0; // Limpar flag
}
// 7. Interrupção de erro passivo
if(int_flag & 0x00000020) { // Erro passivo
can_handle.error_count.error_passive_count++;
if(can_handle.error_callback != NULL) {
can_handle.error_callback(0x20);
}
ECanaRegs.CANGIF0.bit.EPIF = 0; // Limpar flag
}
// Limpar flags globais de interrupção
ECanaRegs.CANGIF0.all = int_flag;
// Confirmar interrupção PIE
PieCtrlRegs.PIEACK.all = PIEACK_GROUP9;
}
// Inicialização das interrupções do CAN
void CAN_InitInterrupts(void)
{
// 1. Habilitar interrupções PIE
EALLOW;
PieVectTable.CANINTA = &CAN_ISR; // Interrupção CAN-A
EDIS;
// 2. Habilitar interrupções de buffer
// Interrupções de buffer 0-15
ECanaRegs.CANMIM.all = 0x0000FFFF; // Habilitar interrupções de buffer 0-15
// 3. Habilitar interrupções globais
ECanaRegs.CANGIM.all = 0x0000001F; // Habilitar todas as interrupções
// 4. Configurar PIE
PieCtrlRegs.PIEIER9.bit.INTx1 = 1; // Habilitar INT9.1 (CAN-A)
// 5. Habilitar INT9 do CPU
IER |= M_INT9;
// 6. Habilitar interrupções globais
EINT;
ERTM;
}
// Habilitar/desabilitar interrupções de buffer
void CAN_EnableInterrupt(Uint16 buffer_num, Uint16 enable)
{
if(buffer_num >= CAN_BUFFER_COUNT) return;
if(enable) {
ECanaRegs.CANMIM.all |= (1 << buffer_num);
} else {
ECanaRegs.CANMIM.all &= ~(1 << buffer_num);
}
}
Tratamento de Erros
// can_error.c
#include "can_driver.h"
// Função de tratamento de erros
void CAN_ErrorHandler(void)
{
Uint16 error_status = ECanaRegs.CANES.all;
// 1. Verificar status de erro
if(error_status & 0x0001) { // Erro de receção
can_handle.error_count.rx_error_count++;
}
if(error_status & 0x0002) { // Erro de transmissão
can_handle.error_count.tx_error_count++;
}
if(error_status & 0x0004) { // Erro passivo
can_handle.state = CAN_STATE_ERROR;
}
if(error_status & 0x0008) { // Bus-off
can_handle.state = CAN_STATE_BUS_OFF;
CAN_BusOffRecovery();
}
// 2. Chamar callback de erro
if(can_handle.error_callback != NULL) {
can_handle.error_callback(error_status);
}
}
// Recuperação de bus-off
void CAN_BusOffRecovery(void)
{
// 1. Entrar no modo de inicialização
ECanaRegs.CANMC.bit.CCR = 1;
while(ECanaRegs.CANES.bit.CCE != 1) {}
// 2. Limpar contadores de erro
ECanaRegs.CANTEC = 0; // Contador de erro de transmissão
ECanaRegs.CANREC = 0; // Contador de erro de receção
// 3. Reconfigurar temporização
CAN_SetBaudRate(can_handle.baud_rate);
// 4. Sair do modo de inicialização
ECanaRegs.CANMC.bit.CCR = 0;
while(ECanaRegs.CANES.bit.CCE != 0) {}
// 5. Reabilitar buffers
ECanaRegs.CANME.all = 0xFFFFFFFF;
can_handle.state = CAN_STATE_READY;
}
// Obter status do CAN
Uint16 CAN_GetStatus(void)
{
Uint16 status = 0;
// Combinar informações de status
status = (can_handle.state << 8) |
(can_handle.error_count.rx_error_count & 0xFF);
return status;
}
Implementação do Protocolo CANopen (Ocpional)
// canopen.c
#include "can_driver.h"
// Dicionário de objetos CANopen
typedef struct {
Uint16 index;
Uint8 subindex;
Uint32 value;
} CANopen_OD_Entry_t;
// Funções do protocolo CANopen
Uint16 CANopen_SendSDO(Uint16 node_id, Uint16 index, Uint8 subindex,
Uint8* data, Uint16 len, Uint8 expedited)
{
Uint8 sdo_data[8];
Uint32 sdo_cmd;
// Construir comando SDO
sdo_cmd = 0x600 + node_id; // Envio SDO do cliente
sdo_data[0] = expedited ? 0x23 : 0x22; // Byte de comando
sdo_data[1] = index & 0xFF;
sdo_data[2] = (index >> 8) & 0xFF;
sdo_data[3] = subindex;
// Copiar dados
for(int i = 0; i < len && i < 4; i++) {
sdo_data[4 + i] = data[i];
}
return CAN_SendExtFrame(sdo_cmd, sdo_data, 8, 16);
}
Uint16 CANopen_SendPDO(Uint16 node_id, Uint8 pdo_num, Uint8* data, Uint16 len)
{
Uint32 pdo_cmd;
switch(pdo_num) {
case 1:
pdo_cmd = 0x200 + node_id;
break;
case 2:
pdo_cmd = 0x300 + node_id;
break;
case 3:
pdo_cmd = 0x400 + node_id;
break;
case 4:
pdo_cmd = 0x500 + node_id;
break;
default:
pdo_cmd = 0x200 + node_id;
}
return CAN_SendExtFrame(pdo_cmd, data, len, 16);
}
void CANopen_SendNMT(Uint8 node_id, Uint8 command)
{
Uint8 nmt_data[2];
nmt_data[0] = command;
nmt_data[1] = node_id;
CAN_SendExtFrame(0x000, nmt_data, 2, 16);
}
Exemplo de Programa Principal
// main.c
#include "DSP2833x_Device.h"
#include "can_driver.h"
// Variáveis globais
CAN_RxMessage_t rx_buffer[10];
Uint16 rx_index = 0;
// Função de callback de receção
void CAN_RxCallback(CAN_RxMessage_t* msg)
{
if(rx_index < 10) {
rx_buffer[rx_index] = *msg;
rx_index++;
}
}
// Função de callback de erro
void CAN_ErrorCallback(Uint16 error_code)
{
// Registrar log de erro
// Pode ser salvo em Flash ou reportado por outra interface
}
int main(void)
{
// 1. Inicializar sistema
InitSysCtrl();
InitPieCtrl();
InitPieVectTable();
// 2. Inicializar CAN, 500kbps
CAN_Init(500);
// 3. Configurar buffers
// Buffer 0: Receber quadro padrão, ID=0x100
CAN_ConfigBuffer(CAN_BUFFER_DIR_RX, 0, 0x100, CAN_FRAME_STD);
// Buffer 1: Receber quadro estendido, ID=0x12345678
CAN_ConfigBuffer(CAN_BUFFER_DIR_RX, 1, 0x12345678, CAN_FRAME_EXT);
// Buffer 16: Buffer de transmissão
CAN_ConfigBuffer(CAN_BUFFER_DIR_TX, 16, 0x200, CAN_FRAME_STD);
// 4. Configurar funções de callback
CAN_SetRxCallback(CAN_RxCallback);
// 5. Loop principal
while(1) {
// Enviar dados de teste
Uint8 tx_data[8] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
CAN_SendStdFrame(0x200, tx_data, 8, 16);
// Processar mensagens recebidas
for(Uint16 i = 0; i < rx_index; i++) {
// Processar mensagem recebida
ProcessCANMessage(&rx_buffer[i]);
}
rx_index = 0;
DELAY_US(1000000); // Atraso de 1 segundo
}
}
// Processar mensagem CAN
void ProcessCANMessage(CAN_RxMessage_t* msg)
{
switch(msg->message_id) {
case 0x100:
// Processar mensagem com ID=0x100
break;
case 0x12345678:
// Processar quadro estendido
break;
}
}
Técnicas de Depuração
1. Uso de analisador lógico
// Adicionar pinos de depuração
#define DEBUG_PIN_SET() GpioDataRegs.GPASET.bit.GPIO0 = 1
#define DEBUG_PIN_CLR() GpioDataRegs.GPACLEAR.bit.GPIO0 = 1
// Adicionar em pontos-chave
DEBUG_PIN_SET();
CAN_SendData(16, data, 8);
DEBUG_PIN_CLR();
2. Monitoramento de estado de erro
void CAN_MonitorTask(void)
{
static Uint32 last_check = 0;
Uint32 current_time = GetTimerCount();
if(current_time - last_check > 1000) { // Verificar a cada 1 segundo
Uint16 status = CAN_GetStatus();
if(status & 0xFF00) { // Verificar bits de status
printf("Status CAN anormal: 0x%04X\n", status);
}
last_check = current_time;
}
}
Problemas Comuns
| Problema | Causa | Solução |
|---|---|---|
| Sem comunicação | Taxa de transmissão incompatível | Verificar taxa em ambos os lados |
| Sem receção de dados | Configuração de buffer incorreta | Verificar direção e ID do buffer |
| Falha no envio | Buffer ocupado | Aguardar conclusão ou usar outro buffer |
| Erro no barramento | Resistência de terminação ausente | Adicionar resistor de 120Ω nas extremidades do barramento |
Configuração de Compilação
1. Configuração do projeto CCS
Caminhos de Inclusão:
- C:\ti\c2000\C28x_FPU_LIB
- ${PROJECT_ROOT}/include
Símbolos Pré-definidos:
_DEBUG
CPU1
2. Arquivo de comando do linker
MEMORY
{
PAGE 0: /* Memória de Programa */
PAGE 1: /* Memória de Dados */
}