我正在使用基于STM32F413RG的定制板,并试图在其上运行一些基于CAN总线的应用程序。
我试图从CAN 1开始,并使用CMSIS库编写了裸机代码以进行发送和接收。
这是三个函数的代码-初始化,发送和接收。
void initCAN()
{
// enable clock
// note: because CAN2 is a "slave CAN" you have to enable CAN1 clock
RCC->APB1ENR |= RCC_APB1ENR_CAN1EN;
// and reset CAN1, so request reset
CAN1->MCR |= CAN_MCR_RESET;
// wait for it to say it has gone to sleep
while ((CAN1->MSR & CAN_MSR_SLAK_Msk) == 1) {}
//CAN1
// enable port A clock
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
__DSB();
// CAN_RX = CAN1R on PA11, so set alt function
GPIOA->MODER &= ~GPIO_MODER_MODER11_Msk;
GPIOA->MODER |= GPIO_MODER_MODER11_1;
// CAN 1 is AF9 (AFSEL 9 = 0b1001 -> bit 3 & bit 0
GPIOA->AFR[1] |= (GPIO_AFRH_AFSEL11_3 | GPIO_AFRH_AFSEL11_0);
// CAN_TX = CAN1T on PA12
GPIOA->MODER &= ~GPIO_MODER_MODER12_Msk;
GPIOA->MODER |= GPIO_MODER_MODER12_1;
// open-drain
GPIOA->OTYPER |= GPIO_OTYPER_OT_11;
GPIOA->OTYPER |= GPIO_OTYPER_OT_12;
// CAN 1 is AF9 (AFSEL 9 = 0b1001 -> bit 3 & bit 0
GPIOA->AFR[1] |= (GPIO_AFRH_AFSEL12_3 | GPIO_AFRH_AFSEL12_0);
//bring it our from sleep by setting the sleep bit in MCR to 0
CAN1->MCR &= ~CAN_MCR_SLEEP_Msk;
//if sleep ACK(SLAK) not zero, wait i.e. exited from sleep
while ((CAN1->MSR & CAN_MSR_SLAK_Msk) != 0) {}
//put CAN 1 to Init mode
CAN1->MCR |= CAN_MCR_INRQ;
// wait for it to say it has gone there
while ((CAN1->MSR & CAN_MSR_INAK_Msk) != CAN_MSR_INAK_Msk) {}
uint32_t APB1Clock = SystemCoreClock/2000000; // in MHz
CAN1->BTR = 0x00050007U;
CAN1->FMR |= CAN_FMR_FINIT;
// and make sure the CANSB value is zero
CAN1->FMR &= ~(CAN_FMR_CAN2SB_Msk);
//Give 14 filter banks to CAN 1 and 2 each
CAN1->FMR |= (((uint32_t) 14) << CAN_FMR_CAN2SB_Pos) & CAN_FMR_CAN2SB_Msk;
// set all as 32 bit filter in identifier mask mode (zeros)
CAN1->FM1R = 0;
// use all as 32 bit filter with mask
CAN1->FS1R |= CAN_FS1R_FSC_Msk;
// assign FIFO0 to CAN1, and FIFO1 to CAN2 (well, all to FIFO0, except filter 14)
CAN1->FFA1R = CAN_FFA1R_FFA14;
// make sure it is deactivated (clear FACT in CAN_FAR)
CAN1->FA1R &= ~CAN_FA1R_FACT0;
CAN1 ->FA1R &= ~CAN_FA1R_FACT14;
// setup a filter that accepts everything (w/ extended id)
// Each filter bank i (i= 0 to 27 in dual CAN configuration and i= 0 to 13 in single CAN configuration)
//is composed of two 32-bit registers, CAN_FiR\[2:1\].
CAN1->sFilterRegister[0].FR1 = CAN_F0R1_FB2;
CAN1->sFilterRegister[0].FR2 = CAN_F0R1_FB2;
CAN1->sFilterRegister[14].FR1 = CAN_F0R1_FB2;
CAN1->sFilterRegister[14].FR2 = CAN_F0R1_FB2;
// now activate filter
CAN1->FA1R |= CAN_FA1R_FACT0;
CAN1->FA1R |= CAN_FA1R_FACT14;
// take out of init mode for filters
CAN1->FMR &= ~CAN_FMR_FINIT;
//loopback mode. need to do it while on init mode
// CAN1->BTR |= CAN_BTR_LBKM;
//bring CAN1 out from init mode.
CAN1->MCR &= ~CAN_MCR_INRQ;
while ((CAN1->MSR & CAN_MSR_INAK_Msk) != 0) {}
}
void sendCAN1( uint32_t pgn, uint8_t bytes[], uint8_t len)
{
// wait for the mailbox to be empty
while ((CAN1->TSR & CAN_TSR_TME0_Msk) == 0) {};
// put this in next empty mailbox
int boxnum = (CAN1->TSR & CAN_TSR_CODE_Msk) >> CAN_TSR_CODE_Pos;
CAN1->sTxMailBox[boxnum].TDTR &= ~CAN_TDT0R_DLC_Msk;
CAN1->sTxMailBox[0].TIR = ((pgn << CAN_TI0R_EXID_Pos) & CAN_TI0R_EXID_Msk) | CAN_TI0R_IDE;
// for standard (11-bit) ids, replace the above with:
// CAN1->sTxMailBox[boxnum].TIR = ((pgn << CAN_TI0R_STID_Pos) & CAN_TI0R_STID_Msk);
CAN1->sTxMailBox[boxnum].TDHR = ((bytes[7]<<CAN_TDH0R_DATA7_Pos) |
(bytes[6]<<CAN_TDH0R_DATA6_Pos) |
(bytes[5]<<CAN_TDH0R_DATA5_Pos) | bytes[4]);
CAN1->sTxMailBox[boxnum].TDLR = ((bytes[3]<<CAN_TDL0R_DATA3_Pos) |
(bytes[2]<<CAN_TDL0R_DATA2_Pos) |
(bytes[1]<<CAN_TDL0R_DATA1_Pos) | bytes[0]);
CAN1->sTxMailBox[boxnum].TDTR = (len << CAN_TDT0R_DLC_Pos) & CAN_TDT0R_DLC_Msk;
CAN1->sTxMailBox[boxnum].TIR |= CAN_TI0R_TXRQ;
}
uint8_t recCAN1()
{
uint8_t data[8];
uint32_t pgn;
uint8_t len;
uint8_t msgcount;
static uint8_t ret = 0;
// check for any msg in FIFO
// we only use FIFO 0 here
msgcount = CAN1->RF0R & CAN_RF0R_FMP0_Msk;
ret += msgcount;
// read them out one at a time
while (msgcount > 0)
{
pgn = CAN1->sFIFOMailBox[0].RIR >> 3;
len = CAN1->sFIFOMailBox[0].RDTR & 0xF;
// NOTE: case fall through is intentional and critical
switch (len)
{
case 8:
data[7] = (CAN1->sFIFOMailBox[0].RDHR >> 24) & 0xFF;
case 7:
data[6] = (CAN1->sFIFOMailBox[0].RDHR >> 16) & 0xFF;
case 6:
data[5] = (CAN1->sFIFOMailBox[0].RDHR >> 8) & 0xFF;
case 5:
data[4] = CAN1->sFIFOMailBox[0].RDHR & 0xFF;
case 4:
data[3] = (CAN1->sFIFOMailBox[0].RDLR >> 24) & 0xFF;
case 3:
data[2] = (CAN1->sFIFOMailBox[0].RDLR >> 16) & 0xFF;
case 2:
data[1] = (CAN1->sFIFOMailBox[0].RDLR >> 8) & 0xFF;
case 1:
data[0] = CAN1->sFIFOMailBox[0].RDLR & 0xFF;
// do nothing as data is empty
}
// process as they are read
// processCAN(pgn, data, len);
// release that mailbox
CAN1->RF0R |= CAN_RF0R_RFOM0;
// update the message count
msgcount = CAN1->RF0R & CAN_RF0R_FMP0_Msk;
}
return ret;
}
从CAN 1发送数据包就可以了。接收时,我看不到接收寄存器上的任何状态更改。但是,我可以在确定信号范围时看到在接收到数据包时从TX引脚发送的ACK。
CAN 1错误状态完全为空(0x0)。
但是,当我在激活环回模式的情况下尝试相同的代码时,我可以在寄存器中看到一条消息,并且我的代码也将其提取。
处于环回模式(指示接收)时,附加CAN 1 RF0R寄存器的屏幕截图。
此作用域(用于RX的通道0和用于TX的通道2)表明它在正常模式下在RX上接收消息,并在其TX上发送回ACK。
我也已经检查了终止,并且罚款。 (增加了120欧姆。无论如何,得到一个ACK,所以我认为这不是问题)。
我对我可能会出错的地方一无所知。 没有明确的错误消息。但是,在正常模式下,Rx消息不会反映在任何一个寄存器上。
答案 0 :(得分:1)
从CAN_FMR寄存器to use CAN1 only: stop the clock on CAN2 and/or set the CAN_MCR.INRQ on CAN2
中的参考手册中,我没有看到在您的代码中明确进行此操作的指令。
此外,在代码注释中,它表示您没有过滤任何内容,但您在CAN_F0R1_FB2
中设置了sFilterRegister
,因此并不是所有内容都可以接受。您发送的ID就是其中之一。