2018-08-11 02:59 AM
Hello friends,
I have to use CAN protocol that I have a lot of devices.
How can I get all data in a lump.
Is there a way by hardware or I have to control data with software like USART.
Any offer?
2018-08-11 05:26 AM
You set the filters to accept all IDs, and then read the whole packets out of the FIFOs as they are received.
2018-08-11 01:33 PM
I use a large array of Rx packets
under interrut, I stuff the received packet into the buffer and exit.
under a worker thread, I check the packet storage and process any new packets.
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 */
}
2018-08-12 01:22 AM
Thank you fot your help ,I will examine that code but it seems very complex
2018-08-12 09:01 AM
I suppose if this stuff were simple we'd all be making minimum wage..
Some of the complexity above comes from buffering the incoming packets so they can be processed in a deferred thread rather than in the interrupt/callback handler.