2018-08-10 02:31 AM
Hi all!
I am new in CAN bus with STM32. I have a project using multi stm32f103 in a CAN network. I want to set up a STM32f103 as a Master CAN device, and others stm32f103 are as a slaver in CAN bus.
I set up a stm32f103 as master, it worked well. because i received successfully my data with a stm32f407 discovery. But when I set up a stm32f103rct6 as a Slaver Can device, it CAN NOT get data, i using interrupt to get data, all parameters is the same with STM32F407. I dont know why????
In CUBE MX set up for CAN. Stm32f103 have only one CAN, and may be only for Master Device, not for set up as a Slaver. Is it right???
anyone can help me?
thanks all!
2018-08-10 09:02 AM
Yes, well the F103 CAN implementation is rather old/limited compared with new iterations of the STM32 designs. It shares resources with the USB.
On F2/F4 there are about 1.5x CAN controllers (ie CAN2 is a parasitic twin)
I'm not sure the Master/Slave context is the same as it might be for SPI or I2C, all CAN nodes can see all bus traffic, you can chose to transmit or not, and selectively filter packets off the wire.
2018-08-10 03:32 PM
I set all my devices to Master Mode, they all transmit and receive correctly.
2018-08-11 07:25 AM
Thanks for your replies!
@TJ Did you used Stm32f103 for your Project?
Can you tell me how to set up for receive data using interrupt.
I debug buy ST-Link and see that: My stm32f103 received correctly data in RXFiFo, Over and full Flag are set. But Interrupt did not happen,
I set options for CAN_RX in CubeMX like that: (see figures)
and in my code, i set up as my attach files above
I think i have something wrong.
Can you check for me ?
thanks!
2018-08-11 07:25 AM
2018-08-11 01:27 PM
here is my code for CAN on the 'F091
I only look at MsgIDs in the ranges 0x400 - 0x5FF and 0x600-0x6FF
This is my Startup init code:
char canRxString [1024];
uint16_t canRxMsgID [64];
uint8_t canRxMsgLength [64];
uint32_t canRxMsgBottomWord [64];
uint32_t canRxMsgTopWord [64];
char canRxHaveSegmentID [64];
char canTxString[1024];
uint16_t canTxMsgID [64];
uint8_t canTxMsgLength [64];
uint32_t canTxMsgBottomWord [64];
uint32_t canTxMsgTopWord [64];
in HAL void CAN_Config() {
:
.
.
.
//##-2- Configure the CAN Filter ###########################################
sFilterConfig.FilterNumber = 0;
sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;
sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
sFilterConfig.FilterIdHigh = 0x400 << 5; //11-bit ID in top bits
sFilterConfig.FilterIdLow = 0x0000;
sFilterConfig.FilterMaskIdHigh = 0x600 << 5; // resolves as 0x0400 - 0x05FF
sFilterConfig.FilterMaskIdLow = 0x0000;
sFilterConfig.FilterFIFOAssignment = 0;
sFilterConfig.FilterActivation = ENABLE;
sFilterConfig.BankNumber = 0;
if (HAL_CAN_ConfigFilter(&hcan, &sFilterConfig) != HAL_OK)
{
// Filter configuration Error
_Error_Handler(__FILE__, __LINE__);
char string[38];
sprintf( string, "Can Filter configuration Error\n\r");
puts1( string);
}
//##-2- Configure the 2nd CAN Filter ###########################################
sFilterConfig.FilterNumber = 1;
sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;
sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
sFilterConfig.FilterIdHigh = 0x600 << 5; //11-bit ID in top bits // command channel
sFilterConfig.FilterIdLow = 0x0000;
sFilterConfig.FilterMaskIdHigh = 0x700 << 5; // resolves as 0x0600 - 0x06FF
sFilterConfig.FilterMaskIdLow = 0x0000;
sFilterConfig.FilterFIFOAssignment = 1;
sFilterConfig.FilterActivation = ENABLE;
sFilterConfig.BankNumber = 1;
if (HAL_CAN_ConfigFilter(&hcan, &sFilterConfig) != HAL_OK)
{
// Filter configuration Error
_Error_Handler(__FILE__, __LINE__);
char string[38];
sprintf( string, "Can Filter configuration Error\n\r");
puts1( string);
}
after HAL Can init code:
void initCairoCan(void) {
CAN_Config();
canRxpointerIN = 0;
canRxMsgIN = 0;
canRxMsgOUT = 0;
canRxMsgTableEMPTY = true;
canRxMsgTableFULL = false;
for (int i = 0; i < 16; i++)
IOCanMsgFlag[i] = false;
__HAL_CAN_ENABLE_IT(&hcan, CAN_IT_FMP1);
__HAL_CAN_ENABLE_IT(&hcan, CAN_IT_FMP0);
canTxMsgIN = 0;
canTxMsgOUT = 0;
canTxMsgTableEMPTY = true;
canTxMsgTableFULL = false;
canTxMsgTableOverflow = false;
canTxMsgOverrun = false;
blockCanTx = false;
}
I edited the initrrupt code :
void CEC_CAN_IRQHandler(void) {
/* USER CODE BEGIN CEC_CAN_IRQn 0 */
CAN_IRQFlag = true;
checkCanRxFifos();
/* USER CODE END CEC_CAN_IRQn 0 */
HAL_CAN_IRQHandler(&hcan);
/* USER CODE BEGIN CEC_CAN_IRQn 1 */
/* USER CODE END CEC_CAN_IRQn 1 */
}
void checkCanRxFifos(void) {
int readCanBytecount;
char canFifo1FullFlag = CAN->RF1R & CAN_RF1R_FMP1;
if (canFifo1FullFlag) {
{
readCanBytecount = (CAN->sFIFOMailBox[1].RDTR & 0x0f);
canRxMsgBottomWord[canRxMsgIN] = CAN->sFIFOMailBox[1].RDLR;
canRxMsgTopWord[canRxMsgIN] = CAN->sFIFOMailBox[1].RDHR;
canRxMsgID[canRxMsgIN] = CAN->sFIFOMailBox[1].RIR >> 21;
CAN->RF1R |= CAN_RF1R_RFOM1; // release FIFO
canRxMsgLength[canRxMsgIN] = readCanBytecount;
canRxMsgIN++;
canRxMsgIN &= 0x3F; // 64 entries only
canRxMsgTableEMPTY = false;
if (canRxMsgIN == canRxMsgOUT) canRxMsgTableFULL = true;
}
CAN->IER |= CAN_IER_FMPIE1; // (11) Set FIFO1 message pending IT enable
}
char canFifo0FullFlag = CAN->RF0R & CAN_RF0R_FMP0;
if (canFifo0FullFlag) {
{
readCanBytecount = (CAN->sFIFOMailBox[0].RDTR & 0x0f);
canRxMsgBottomWord[canRxMsgIN] = CAN->sFIFOMailBox[0].RDLR;
canRxMsgTopWord[canRxMsgIN] = CAN->sFIFOMailBox[0].RDHR;
uint32_t canRxmsgID = CAN->sFIFOMailBox[0].RIR >> 21;
CAN->RF0R |= CAN_RF0R_RFOM0; // release FIFO
if(canRxMsgTableFULL) {
canRxMsgTableOverflow = true; // now dump new frame...
}else {
canRxMsgID[canRxMsgIN] = canRxmsgID;
canRxMsgLength[canRxMsgIN] = readCanBytecount;
canRxMsgIN++;
canRxMsgIN &= 0x3F; // 64 entries only
canRxMsgTableEMPTY = false;
if (canRxMsgIN == canRxMsgOUT)
canRxMsgTableFULL = true;
}
//length = sprintf(string + length,"%08X, %08X :W",canFifoBuf.d32[0],canFifoBuf.d32[1]);
// for( int i = 0; i < readCanBytecount; i++){
// canRxBuffer[canRxpointerIN++] = canFifoBuf.d8[i];
// canRxpointerIN &= 0xFF;
// if (canRxpointerIN == canRxpointerOUT ) CanRxbufferOverrun = true;
// //length += sprintf(string + length,"%02X, ",canFifoBuf.d8[i]);
// }
//sprintf(string + length -2,"\n\r"); // remove 2 bytes, the last comma and space
}
CAN->IER |= CAN_IER_FMPIE0; // (11) Set FIFO1 message pending IT enable
}
// if (length >0) puts(string);
}
inside my foreground process I call DoCan, which only checks all new RXframes before it leaves.
void DoCan(void) {
char string[1024];
int length = 0;
if (canRxMsgTableOverflow) {
canRxMsgTableOverflow = false;
sprintf(string, "CanFlags Table has Overflowed, new frames are being dumped\n\r"); // now dump new frame...
puts1(string);
}
if (canRxMsgTableFULL) {
canRxMsgTableFULL = false;
sprintf(string, "CanFlags Table is Full, probably missing frames now\n\r");
puts1(string);
}
if (checkCanRxSensorFreshDataCompleted())
showCanSensorADCArray();
if (haveCanString)
showCanString();
while (!canRxMsgTableEMPTY) {
int canRxMsgBytecount = canRxMsgLength[canRxMsgOUT];
int16_t dataChannel = canRxMsgID[canRxMsgOUT];
canRxCmdFifoBuf.d32[0] = canRxMsgBottomWord[canRxMsgOUT];
canRxCmdFifoBuf.d32[1] = canRxMsgTopWord[canRxMsgOUT];
// zero data within RxCanFrameBuffer to make sure we only use valid data, but not necessary
canRxMsgID[canRxMsgOUT] = 0;
canRxMsgBottomWord[canRxMsgOUT] = 0;
canRxMsgTopWord[canRxMsgOUT] = 0;
canRxMsgLength[canRxMsgOUT] = 0;
/* if (dataChannel == 0x418)
while(1);
if (dataChannel == 0x408)
while(1);
*/
canRxMsgTableFULL = false;
canRxMsgOUT++;
canRxMsgOUT &= 0x3f; // only 16 messages
if(canRxMsgOUT == canRxMsgIN) canRxMsgTableEMPTY = true;
.
.
.
.
process frame here
the transmit function
if ((CAN->TSR & CAN_TSR_TME0) == CAN_TSR_TME0) // (1)
{
CAN->sTxMailBox[0].TDTR = canTxMsgLength[canTxMsgOUT]; // (2) length
CAN->sTxMailBox[0].TDLR = canTxMsgBottomWord[canTxMsgOUT]; // (3) 4bytes
CAN->sTxMailBox[0].TDHR = canTxMsgTopWord[canTxMsgOUT]; // (3) 4bytes
CAN->sTxMailBox[0].TIR = ((uint32_t)canTxMsgID[canTxMsgOUT] << 21 | CAN_TI0R_TXRQ); // (4) // send it now if the line is idle
}
if ((CAN->TSR & CAN_TSR_TME1) == CAN_TSR_TME1) // (1)
{
if ((CAN->TSR & CAN_TSR_TME2) == CAN_TSR_TME2) // (1)
{
void CAN1_RX0_IRQHandler(void)
{
/* USER CODE BEGIN CAN1_RX0_IRQn 0 */
//CAN_Rx0_IRQFlag = true;
//CAN_IRQFlag = true;
checkCanRxFifos();
/* USER CODE END CAN1_RX0_IRQn 0 */
HAL_CAN_IRQHandler(&hcan1);
/* USER CODE BEGIN CAN1_RX0_IRQn 1 */
/* USER CODE END CAN1_RX0_IRQn 1 */
}
/**
* @brief This function handles CAN1 RX1 interrupt.
*/
void CAN1_RX1_IRQHandler(void)
{
/* USER CODE BEGIN CAN1_RX1_IRQn 0 */
// CAN_Rx1_IRQFlag = true;
// CAN_IRQFlag = true;
checkCanRxFifos();
/* USER CODE END CAN1_RX1_IRQn 0 */
HAL_CAN_IRQHandler(&hcan1);
/* USER CODE BEGIN CAN1_RX1_IRQn 1 */
/* USER CODE END CAN1_RX1_IRQn 1 */
}