Using specification UM1884 for the STM32L4, I have (essentially) programmed the following in main():
/* USER CODE BEGIN PTD */
#define NOJI_DEFAULT_ID 102
/* USER CODE END PTD */
/* USER CODE BEGIN 0 */
uint8_t currentID = NOJI_DEFAULT_ID;
CAN_TxHeaderTypeDef txHeader;
CAN_RxHeaderTypeDef rxHeader;
uint8_t txData[8];
uint8_t rxData[8];
uint32_t txMailbox;
int dataCheck = 0;
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *Nhcan)
{
static uint32_t count = 0;
count++;
memset((void *) &rxHeader, 0, sizeof(CAN_RxHeaderTypeDef));
memset((void *) rxData, 0, 8);
HAL_CAN_GetRxMessage(Nhcan, CAN_RX_FIFO0, &rxHeader, rxData);
if (rxHeader.DLC == 2)
{
dataCheck = 1;
}
}
/* USER CODE END 0 */
/* USER CODE BEGIN 2 */
HAL_StatusTypeDef status = HAL_OK;
CAN_FilterTypeDef canFilter;
memset((void *) &canFilter, 0, sizeof(CAN_FilterTypeDef));
canFilter.FilterActivation = CAN_FILTER_ENABLE;
canFilter.FilterBank = 10;
canFilter.FilterFIFOAssignment = CAN_RX_FIFO0;
canFilter.FilterIdHigh = currentID << 5;
canFilter.FilterMaskIdHigh = 0xFFE0;
canFilter.FilterMode = CAN_FILTERMODE_IDMASK;
canFilter.FilterScale = CAN_FILTERSCALE_32BIT;
canFilter.SlaveStartFilterBank = 18;
status = HAL_CAN_ConfigFilter(&hcan1, &canFilter);
status |= HAL_CAN_Start(&hcan1);
status |= HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING);
memset((void *) &txHeader, 0, sizeof(CAN_TxHeaderTypeDef));
txHeader.IDE = CAN_ID_STD;
txHeader.RTR = CAN_RTR_DATA;
txHeader.StdId = currentID; // 0x66
txHeader.DLC = 2;
txHeader.TransmitGlobalTime = DISABLE;
memset((void *) txData, 0, 8);
txData[0] = 0xD7;
txData[1] = 0xC3;
status |= HAL_CAN_AddTxMessage(&hcan1, &txHeader, txData, &txMailbox);
/* USER CODE END 2 */
and my device is not seen on the CAN bus, using DroneCAN, MissionPlanner, or any other app. What am I missing, to get my device advertised on the CAN bus? My ISR is never hit.
Related
I am trying to transmit through CAN using dsPIC33EV256GM106 and MCC to a raspberry Pi.
I am new to CAN Bus and in c. I have configured CAN Bus and DMA via MCC, and I have called the functions in main.c. but nothing arrives in the Raspberry Pi. Here is my main.c, can.c and some pictures of MCC. If anyone has any ideas, how I can change the code to make the CAN bus work, I would appreciate any help.CAN Bus configuration
DMA
System_Module
#include "mcc_generated_files/system.h"
#include "mcc_generated_files/can_types.h"
#include <stdio.h>
/*
Main application
*/
uCAN_MSG msg;
int main(void)
{
// initialize the device
SYSTEM_Initialize();
CAN1_TransmitEnable();
CAN1_ReceiveEnable();
CAN1_OperationModeSet(CAN_CONFIGURATION_MODE);
msg.frame.id = 0x123;
msg.frame.idType = CAN_FRAME_STD;
msg.frame.msgtype = CAN_MSG_DATA;
msg.frame.dlc = 0x08;
msg.frame.data0 = 0x01;
msg.frame.data1 = 0x02;
msg.frame.data2 = 0x03;
msg.frame.data3 = 0x04;
msg.frame.data4 = 0x05;
msg.frame.data5 = 0x06;
msg.frame.data6 = 0x07;
msg.frame.data7 = 0x08;
while (1)
{
CAN1_Transmit(CAN_PRIORITY_HIGH, &msg);
}
return 1;
}
The pictures show the configuration of DMA and timer in MCC.
enter image description here
enter image description here
#include "can1.h"
#include "dma.h"
#define CAN1_TX_DMA_CHANNEL DMA_CHANNEL_0
#define CAN1_RX_DMA_CHANNEL DMA_CHANNEL_2
/* Valid options are 4, 6, 8, 12, 16, 24, or 32. */
#define CAN1_MESSAGE_BUFFERS 32
#define CAN1_FIFO_STARTING_BUFFER 0x1
#define CAN1_TX_BUFFER_COUNT 1
#define CAN1_RX_BUFFER_MSG_DATA_SIZE 8U // CAN RX Buffer Message object data field size
/* Private type definitions */
/******************************************************************************/
typedef struct __attribute__((packed))
{
unsigned priority :2;
unsigned remote_transmit_enable :1;
unsigned send_request :1;
unsigned error :1;
unsigned lost_arbitration :1;
unsigned message_aborted :1;
unsigned transmit_enabled :1;
} CAN1_TX_CONTROLS;
/**
Section: Private Variable Definitions
*/
/* This alignment is required because of the DMA's peripheral indirect
* addressing mode. */
static unsigned int can1msgBuf [CAN1_MESSAGE_BUFFERS][8] __attribute__((aligned(32 * 8 * 2)));
static void CAN1_DMACopy(uint8_t buffer_number, CAN_MSG_OBJ *message);
static void CAN1_MessageToBuffer(uint16_t* buffer, CAN_MSG_OBJ *message);
// CAN1 Default Interrupt Handler
static void (*CAN1_BusErrorHandler)(void) = NULL;
static void (*CAN1_TxErrorPassiveHandler)(void) = NULL;
static void (*CAN1_RxErrorPassiveHandler)(void) = NULL;
static void (*CAN1_BusWakeUpActivityInterruptHandler)(void) = NULL;
static void (*CAN1_RxBufferInterruptHandler)(void) = NULL;
static void (*CAN1_RxBufferOverFlowInterruptHandler)(void) = NULL;
/**
#Summary
Read the message object from Receive buffer and update to the user message object
pointer.
#Description
This routine read the message object from Receive buffer and update to the user
message object pointer.
#Preconditions
CAN1_Initialize function should be called before calling this function.
#Param
bufferNumber - A buffer number is in the Receive buffer where the message would
be stored.
message - pointer to the CAN1 Receive message object.
#Returns
None
#Example
None
*/
static void CAN1_DMACopy(uint8_t buffer_number, CAN_MSG_OBJ *message)
{
uint16_t ide=0;
uint16_t rtr=0;
uint32_t id=0;
/* read word 0 to see the message type */
ide=can1msgBuf[buffer_number][0] & 0x0001U;
/* check to see what type of message it is */
/* message is standard identifier */
if(ide==0U)
{
message->msgId =(can1msgBuf[buffer_number][0] & 0x1FFCU) >> 2U;
message->field.idType = CAN_FRAME_STD;
rtr=can1msgBuf[buffer_number][0] & 0x0002U;
}
/* message is extended identifier */
else
{
id=can1msgBuf[buffer_number][0] & 0x1FFCU;
message->msgId = id << 16U;
message->msgId += ( ((uint32_t) can1msgBuf[buffer_number][1] & (uint32_t)0x0FFF) << 6U );
message->msgId += ( ((uint32_t) can1msgBuf[buffer_number][2] & (uint32_t)0xFC00U) >> 10U );
message->field.idType = CAN_FRAME_EXT;
rtr=can1msgBuf[buffer_number][2] & 0x0200;
}
/* check to see what type of message it is */
/* RTR message */
if(rtr != 0U)
{
/* to be defined ?*/
message->field.frameType = CAN_FRAME_RTR;
}
/* normal message */
else
{
message->field.frameType = CAN_FRAME_DATA;
message->data[0] =(uint8_t) can1msgBuf[buffer_number][3];
message->data[1] =(uint8_t) ((can1msgBuf[buffer_number][3] & 0xFF00U) >> 8U);
message->data[2] =(uint8_t) can1msgBuf[buffer_number][4];
message->data[3] =(uint8_t) ((can1msgBuf[buffer_number][4] & 0xFF00U) >> 8U);
message->data[4] =(uint8_t) can1msgBuf[buffer_number][5];
message->data[5] =(uint8_t) ((can1msgBuf[buffer_number][5] & 0xFF00U) >> 8U);
message->data[6] =(uint8_t) can1msgBuf[buffer_number][6];
message->data[7] =(uint8_t) ((can1msgBuf[buffer_number][6] & 0xFF00U) >> 8U);
message->field.dlc =(uint8_t) (can1msgBuf[buffer_number][2] & 0x000FU);
}
}
/**
#Summary
Read the message object from user input and update to the CAN1 TX buffer.
#Description
This routine Read the message object from user input and update to the CAN1
TX buffer.
#Preconditions
CAN1_Initialize function should be called before calling this function.
#Param
buffer - pointer to the CAN1 Message object.
message - pointer to the CAN1 transmit message object.
#Returns
None
#Example
None
*/
static void CAN1_MessageToBuffer(uint16_t* buffer, CAN_MSG_OBJ* message)
{
if(message->field.idType == CAN_FRAME_STD)
{
buffer[0]= (message->msgId & 0x000007FF) << 2;
buffer[1]= 0;
buffer[2]= message->field.dlc & 0x0F;
}
else
{
buffer[0]= ( ( (uint16_t)(message->msgId >> 16 ) & 0x1FFC ) ) | 0x3;
buffer[1]= (uint16_t)(message->msgId >> 6) & 0x0FFF;
buffer[2]= (message->field.dlc & 0x0F) + ( (uint16_t)(message->msgId << 10) & 0xFC00);
}
if(message->data != NULL)
{
buffer[3]= ((message->data[1])<<8) + message->data[0];
buffer[4]= ((message->data[3])<<8) + message->data[2];
buffer[5]= ((message->data[5])<<8) + message->data[4];
buffer[6]= ((message->data[7])<<8) + message->data[6];
}
}
/**
Section: CAN1 APIs
*/
void CAN1_Initialize(void)
{
// Disable interrupts before the Initialization
IEC2bits.C1IE = 0;
C1INTE = 0;
// set the CAN1_initialize module to the options selected in the User Interface
/* put the module in configuration mode */
C1CTRL1bits.REQOP = CAN_CONFIGURATION_MODE;
while(C1CTRL1bits.OPMODE != CAN_CONFIGURATION_MODE);
/* Set up the baud rate*/
C1CFG1 = 0x03; //BRP TQ = (2 x 4)/FCAN; SJW 1 x TQ;
C1CFG2 = 0x43BE; //WAKFIL enabled; SEG2PHTS Freely programmable; SEG2PH 4 x TQ; SEG1PH 8 x TQ; PRSEG 7 x TQ; SAM Once at the sample point;
C1FCTRL = 0xC001; //FSA Transmit/Receive Buffer TRB1; DMABS 32;
C1FEN1 = 0x01; //FLTEN8 disabled; FLTEN7 disabled; FLTEN9 disabled; FLTEN0 enabled; FLTEN2 disabled; FLTEN10 disabled; FLTEN1 disabled; FLTEN11 disabled; FLTEN4 disabled; FLTEN3 disabled; FLTEN6 disabled; FLTEN5 disabled; FLTEN12 disabled; FLTEN13 disabled; FLTEN14 disabled; FLTEN15 disabled;
C1CTRL1 = 0x00; //CANCKS FOSC/2; CSIDL disabled; ABAT disabled; REQOP Sets Normal Operation Mode; WIN Uses buffer window; CANCAP disabled;
/* Filter configuration */
/* enable window to access the filter configuration registers */
/* use filter window*/
C1CTRL1bits.WIN=1;
/* select acceptance masks for filters */
C1FMSKSEL1bits.F0MSK = 0x0; //Select Mask 0 for Filter 0
/* Configure the masks */
C1RXM0SIDbits.SID = 0x7ff;
C1RXM1SIDbits.SID = 0x0;
C1RXM2SIDbits.SID = 0x0;
C1RXM0SIDbits.EID = 0x0;
C1RXM1SIDbits.EID = 0x0;
C1RXM2SIDbits.EID = 0x0;
C1RXM0EID = 0x00;
C1RXM1EID = 0x00;
C1RXM2EID = 0x00;
C1RXM0SIDbits.MIDE = 0x0;
C1RXM1SIDbits.MIDE = 0x0;
C1RXM2SIDbits.MIDE = 0x0;
/* Configure the filters */
C1RXF0SIDbits.SID = 0x123;
C1RXF0SIDbits.EID = 0x0;
C1RXF0EID = 0x00;
C1RXF0SIDbits.EXIDE = 0x0;
/* FIFO Mode */
C1BUFPNT1bits.F0BP = 0xf; //Filter 0 uses FIFO
/* clear window bit to access CAN1 control registers */
C1CTRL1bits.WIN=0;
/*configure CAN1 Transmit/Receive buffer settings*/
C1TR01CONbits.TXEN0 = 0x1; // Buffer 0 is a Transmit Buffer
C1TR01CONbits.TXEN1 = 0x0; // Buffer 1 is a Receive Buffer
C1TR23CONbits.TXEN2 = 0x0; // Buffer 2 is a Receive Buffer
C1TR23CONbits.TXEN3 = 0x0; // Buffer 3 is a Receive Buffer
C1TR45CONbits.TXEN4 = 0x0; // Buffer 4 is a Receive Buffer
C1TR45CONbits.TXEN5 = 0x0; // Buffer 5 is a Receive Buffer
C1TR67CONbits.TXEN6 = 0x0; // Buffer 6 is a Receive Buffer
C1TR67CONbits.TXEN7 = 0x0; // Buffer 7 is a Receive Buffer
C1TR01CONbits.TX0PRI = 0x0; // Message Buffer 0 Priority Level
C1TR01CONbits.TX1PRI = 0x0; // Message Buffer 1 Priority Level
C1TR23CONbits.TX2PRI = 0x0; // Message Buffer 2 Priority Level
C1TR23CONbits.TX3PRI = 0x0; // Message Buffer 3 Priority Level
C1TR45CONbits.TX4PRI = 0x0; // Message Buffer 4 Priority Level
C1TR45CONbits.TX5PRI = 0x0; // Message Buffer 5 Priority Level
C1TR67CONbits.TX6PRI = 0x0; // Message Buffer 6 Priority Level
C1TR67CONbits.TX7PRI = 0x0; // Message Buffer 7 Priority Level
/* clear the buffer and overflow flags */
C1RXFUL1 = 0x0000;
C1RXFUL2 = 0x0000;
C1RXOVF1 = 0x0000;
C1RXOVF2 = 0x0000;
/* configure the device to interrupt on the receive buffer full flag */
/* clear the buffer full flags */
C1INTFbits.RBIF = 0;
/* put the module in normal mode */
C1CTRL1bits.REQOP = CAN_NORMAL_OPERATION_MODE;
while(C1CTRL1bits.OPMODE != CAN_NORMAL_OPERATION_MODE);
/* Initialize Interrupt Handler*/
CAN1_SetBusErrorHandler(&CAN1_DefaultBusErrorHandler);
CAN1_SetTxErrorPassiveHandler(&CAN1_DefaultTxErrorPassiveHandler);
CAN1_SetRxErrorPassiveHandler(&CAN1_DefaultRxErrorPassiveHandler);
CAN1_SetBusWakeUpActivityInterruptHandler(&CAN1_DefaultBusWakeUpActivityHandler);
CAN1_SetRxBufferInterruptHandler(&CAN1_DefaultReceiveBufferHandler);
CAN1_SetRxBufferOverFlowInterruptHandler(&CAN1_DefaultRxBufferOverFlowHandler);
/* Enable CAN1 Interrupt */
IEC2bits.C1IE = 1;
/* Enable Receive interrupt */
C1INTEbits.RBIE = 1;
/* Enable Error interrupt*/
C1INTEbits.ERRIE = 1;
/* Enable Receive buffer Overflow interrupt */
C1INTEbits.RBOVIE = 1;
}
void CAN1_TransmitEnable()
{
/* setup channel 0 for peripheral indirect addressing mode
normal operation, word operation and select as Tx to peripheral */
/* DMA_PeripheralIrqNumberSet and DMA_TransferCountSet would be done in the
DMA */
/* setup the address of the peripheral CAN1 (C1TXD) */
DMA_PeripheralAddressSet(CAN1_TX_DMA_CHANNEL, (uint16_t) &C1TXD);
/* DPSRAM start address offset value */
DMA_StartAddressASet(CAN1_TX_DMA_CHANNEL, (uint16_t) (&can1msgBuf));
/* enable the channel */
DMA_ChannelEnable(CAN1_TX_DMA_CHANNEL);
}
void CAN1_ReceiveEnable()
{
/* setup DMA channel for peripheral indirect addressing mode
normal operation, word operation and select as Rx to peripheral */
/* setup the address of the peripheral CAN1 (C1RXD) */
/* DMA_TransferCountSet and DMA_PeripheralIrqNumberSet would be set in
the DMA_Initialize function */
DMA_PeripheralAddressSet(CAN1_RX_DMA_CHANNEL, (uint16_t) &C1RXD);
/* DPSRAM start address offset value */
DMA_StartAddressASet(CAN1_RX_DMA_CHANNEL, (uint16_t) (&can1msgBuf) );
/* enable the channel */
DMA_ChannelEnable(CAN1_RX_DMA_CHANNEL);
}
CAN_OP_MODE_STATUS CAN1_OperationModeSet(const CAN_OP_MODES requestMode)
{
CAN_OP_MODE_STATUS status = CAN_OP_MODE_REQUEST_SUCCESS;
if((CAN_CONFIGURATION_MODE == CAN1_OperationModeGet()) || (requestMode == CAN_DISABLE_MODE)
|| (requestMode == CAN_CONFIGURATION_MODE))
{
C1CTRL1bits.REQOP = requestMode;
while(C1CTRL1bits.OPMODE != requestMode);
}
else
{
status = CAN_OP_MODE_REQUEST_FAIL;
}
return status;
}
CAN_OP_MODES CAN1_OperationModeGet(void)
{
return C1CTRL1bits.OPMODE;
}
CAN_TX_MSG_REQUEST_STATUS CAN1_Transmit(CAN_TX_PRIOIRTY priority, CAN_MSG_OBJ *sendCanMsg)
{
CAN_TX_MSG_REQUEST_STATUS txMsgStatus = CAN_TX_MSG_REQUEST_SUCCESS;
CAN1_TX_CONTROLS * pTxControls = (CAN1_TX_CONTROLS*)&C1TR01CON;
uint_fast8_t i;
bool messageSent = false;
// CAN 2.0 mode DLC supports upto 8 byte
if(sendCanMsg->field.dlc > CAN_DLC_8)
{
txMsgStatus |= CAN_TX_MSG_REQUEST_DLC_ERROR;
}
if(CAN1_TX_BUFFER_COUNT > 0)
{
for(i=0; i<CAN1_TX_BUFFER_COUNT; i++)
{
if(pTxControls->transmit_enabled == 1)
{
if (pTxControls->send_request == 0)
{
CAN1_MessageToBuffer(&can1msgBuf[i][0], sendCanMsg);
pTxControls->priority = priority;
/* set the message for transmission */
pTxControls->send_request = 1;
messageSent = true;
break;
}
}
pTxControls++;
}
}
if(messageSent == false)
{
txMsgStatus |= CAN_TX_MSG_REQUEST_BUFFER_FULL;
}
return txMsgStatus;
}
bool CAN1_Receive(CAN_MSG_OBJ *recCanMsg)
{
uint_fast8_t currentBuffer;
uint_fast8_t shiftAmount;
bool messageReceived = false;
uint16_t receptionFlags;
if(C1INTFbits.RBOVIF == 1)
{
C1INTFbits.RBOVIF = 0;
/* Receive buffer overflow occured, call the notification function */
if(CAN1_RxBufferOverFlowInterruptHandler)
{
CAN1_RxBufferOverFlowInterruptHandler();
}
return messageReceived;
}
if(recCanMsg->data == NULL)
{
return messageReceived;
}
currentBuffer = C1FIFObits.FNRB;
if( currentBuffer < 16)
{
receptionFlags = C1RXFUL1;
shiftAmount = currentBuffer;
}
else
{
receptionFlags = C1RXFUL2;
shiftAmount = currentBuffer - 16;
}
if (((receptionFlags >> shiftAmount ) & 0x1) == 0x1)
{
CAN1_DMACopy(currentBuffer, recCanMsg);
if( currentBuffer < 16)
{
C1RXFUL1 &= ~(1 << shiftAmount);
}
else
{
C1RXFUL2 &= ~(1 << shiftAmount);
}
messageReceived = true;
}
return (messageReceived);
}
bool CAN1_IsBusOff()
{
return C1INTFbits.TXBO;
}
bool CAN1_IsRXErrorPassive()
{
return (C1INTFbits.RXBP);
}
bool CAN1_IsRxErrorWarning(void)
{
return (C1INTFbits.RXWAR);
}
bool CAN1_IsRxErrorActive(void)
{
bool errorState = false;
if((0 < C1ECbits.RERRCNT) && (C1ECbits.RERRCNT < 128))
{
errorState = true;
}
return errorState;
}
bool CAN1_IsTXErrorPassive()
{
return (C1INTFbits.TXBP);
}
bool CAN1_IsTxErrorWarning(void)
{
return (C1INTFbits.TXWAR);
}
bool CAN1_IsTxErrorActive(void)
{
bool errorState = false;
if((0 < C1ECbits.TERRCNT) && (C1ECbits.TERRCNT < 128))
{
errorState = true;
}
return errorState;
}
uint8_t CAN1_ReceivedMessageCountGet()
{
uint_fast8_t messageCount;
uint_fast8_t currentBuffer;
uint16_t receptionFlags;
messageCount = 0;
#if (CAN1_FIFO_STARTING_BUFFER<16)
/* Check any message in buffer 0 to buffer 15*/
receptionFlags = C1RXFUL1;
if (receptionFlags != 0)
{
/* check whether a message is received */
for (currentBuffer=0 ; currentBuffer < 16; currentBuffer++)
{
if (((receptionFlags >> currentBuffer ) & 0x1) == 0x1)
{
messageCount++;
}
}
}
#endif
/* Check any message in buffer 16 to buffer 32*/
receptionFlags = C1RXFUL2;
if (receptionFlags != 0)
{
/* check whether a message is received */
for (currentBuffer=0 ; currentBuffer < 16; currentBuffer++)
{
if (((receptionFlags >> currentBuffer ) & 0x1) == 0x1)
{
messageCount++;
}
}
}
return (messageCount);
}
void CAN1_Sleep(void)
{
C1INTFbits.WAKIF = 0;
C1INTEbits.WAKIE = 1;
/* put the module in disable mode */
C1CTRL1bits.REQOP = CAN_DISABLE_MODE;
while(C1CTRL1bits.OPMODE != CAN_DISABLE_MODE);
//Wake up from sleep should set the CAN1 module straight into Normal mode
}
void __attribute__((weak)) CAN1_DefaultBusErrorHandler(void)
{
CAN1_CallbackBusOff();
}
void CAN1_SetBusErrorHandler(void *handler)
{
CAN1_BusErrorHandler = handler;
}
void __attribute__((weak)) CAN1_DefaultTxErrorPassiveHandler(void)
{
CAN1_CallbackTxErrorPassive();
}
void CAN1_SetTxErrorPassiveHandler(void *handler)
{
CAN1_TxErrorPassiveHandler = handler;
}
void __attribute__((weak)) CAN1_DefaultRxErrorPassiveHandler(void)
{
CAN1_CallbackRxErrorPassive();
}
void CAN1_SetRxErrorPassiveHandler(void *handler)
{
CAN1_RxErrorPassiveHandler = handler;
}
void __attribute__((weak)) CAN1_DefaultBusWakeUpActivityHandler(void)
{
}
void CAN1_SetBusWakeUpActivityInterruptHandler(void *handler)
{
CAN1_BusWakeUpActivityInterruptHandler = handler;
}
void __attribute__((weak)) CAN1_DefaultReceiveBufferHandler(void)
{
CAN1_CallbackMessageReceived();
}
void CAN1_SetRxBufferInterruptHandler(void *handler)
{
CAN1_RxBufferInterruptHandler = handler;
}
void __attribute__((weak)) CAN1_DefaultRxBufferOverFlowHandler(void)
{
CAN1_CallbackRxBufferOverflow();
}
void CAN1_SetRxBufferOverFlowInterruptHandler(void *handler)
{
CAN1_RxBufferOverFlowInterruptHandler = handler;
}
void __attribute__((__interrupt__, no_auto_psv)) _C1Interrupt(void)
{
if (C1INTFbits.ERRIF)
{
if (C1INTFbits.TXBO == 1)
{
if(CAN1_BusErrorHandler)
{
CAN1_BusErrorHandler();
}
}
if (C1INTFbits.TXBP == 1)
{
if(CAN1_TxErrorPassiveHandler)
{
CAN1_TxErrorPassiveHandler();
}
}
if (C1INTFbits.RXBP == 1)
{
if(CAN1_RxErrorPassiveHandler)
{
CAN1_RxErrorPassiveHandler();
}
}
/* Call error notification function */
C1INTFbits.ERRIF = 0;
}
if(C1INTFbits.RBIF)
{
if(CAN1_RxBufferInterruptHandler)
{
CAN1_RxBufferInterruptHandler();
}
C1INTFbits.RBIF = 0;
}
if(C1INTFbits.WAKIF)
{
if(CAN1_BusWakeUpActivityInterruptHandler)
{
CAN1_BusWakeUpActivityInterruptHandler();
}
C1INTFbits.WAKIF = 0;
}
IFS2bits.C1IF = 0;
}
/*******************************************************************************
!!! Deprecated Definitions and APIs !!!
!!! These functions will not be supported in future releases !!!
*******************************************************************************/
/******************************************************************************
*
* Function: CAN1_transmit
* Description: Transmits the message from user buffer to CAN1 buffer
* as per the buffer number allocated.
* Allocation of the buffer number is done by user
*
* Arguments: priority : priority of the message to be transmitted
* sendCanMsg: pointer to the message object
*
* Return Value: true - Transmit successful
* false - Transmit failure
******************************************************************************/
bool CAN1_transmit(CAN_TX_PRIOIRTY priority, uCAN_MSG *sendCanMsg)
{
uint8_t msgObjData[8] = {0};
CAN_MSG_OBJ txCanMsg;
txCanMsg.data = msgObjData;
txCanMsg.msgId = sendCanMsg->frame.id;
txCanMsg.field.idType = sendCanMsg->frame.idType;
txCanMsg.field.frameType = sendCanMsg->frame.msgtype;
txCanMsg.field.dlc = sendCanMsg->frame.dlc;
txCanMsg.data[0] = sendCanMsg->frame.data0;
txCanMsg.data[1] = sendCanMsg->frame.data1;
txCanMsg.data[2] = sendCanMsg->frame.data2;
txCanMsg.data[3] = sendCanMsg->frame.data3;
txCanMsg.data[4] = sendCanMsg->frame.data4;
txCanMsg.data[5] = sendCanMsg->frame.data5;
txCanMsg.data[6] = sendCanMsg->frame.data6;
txCanMsg.data[7] = sendCanMsg->frame.data7;
return (CAN1_Transmit(priority, &txCanMsg));
}
/******************************************************************************
*
* Function: CAN1_receive
* Description: Receives the message from CAN1 buffer to user buffer
*
* Arguments: recCanMsg: pointer to the message object
*
* Return Value: true - Receive successful
* false - Receive failure
******************************************************************************/
bool CAN1_receive(uCAN_MSG *recCanMsg)
{
bool messageReceived = false;
uint8_t msgObjData[8] = {0};
CAN_MSG_OBJ rxCanMsg;
rxCanMsg.data = msgObjData;
if(true == CAN1_Receive(&rxCanMsg))
{
recCanMsg->frame.id = rxCanMsg.msgId;
recCanMsg->frame.idType = rxCanMsg.field.idType;
if(rxCanMsg.field.frameType == CAN_FRAME_RTR)
{
recCanMsg->frame.msgtype = CAN_MSG_RTR;
}
else
{
recCanMsg->frame.msgtype = CAN_MSG_DATA;
}
recCanMsg->frame.data0 = rxCanMsg.data[0];
recCanMsg->frame.data1 = rxCanMsg.data[1];
recCanMsg->frame.data2 = rxCanMsg.data[2];
recCanMsg->frame.data3 = rxCanMsg.data[3];
recCanMsg->frame.data4 = rxCanMsg.data[4];
recCanMsg->frame.data5 = rxCanMsg.data[5];
recCanMsg->frame.data6 = rxCanMsg.data[6];
recCanMsg->frame.data7 = rxCanMsg.data[7];
recCanMsg->frame.dlc = rxCanMsg.field.dlc;
messageReceived = true;
}
return (messageReceived);
}
/******************************************************************************
*
* Function: CAN1_isBusOff
* Description: Checks whether the transmitter in Bus off state
*
* Return Value: true - Transmitter in Bus Off state
* false - Transmitter not in Bus Off state
******************************************************************************/
bool CAN1_isBusOff()
{
return C1INTFbits.TXBO;
}
/******************************************************************************
*
* Function: CAN1_isRXErrorPassive
* Description: Checks whether the receive in error passive state
*
* Return Value: true - Receiver in Error Passive state
* false - Receiver not in Error Passive state
******************************************************************************/
bool CAN1_isRXErrorPassive()
{
return C1INTFbits.RXBP;
}
/******************************************************************************
*
* Function: CAN1_isTXErrorPassive
* Description: Checks whether the transmitter in error passive state
*
* Return Value: true - Transmitter in Error Passive state
* false - Transmitter not in Error Passive state
******************************************************************************/
bool CAN1_isTXErrorPassive()
{
return (C1INTFbits.TXBP);
}
/******************************************************************************
*
* Function: CAN1_messagesInBuffer
* Description: returns the number of messages that are received
*
* Return Value: Number of message received
******************************************************************************/
uint8_t CAN1_messagesInBuffer()
{
uint_fast8_t messageCount;
uint_fast8_t currentBuffer;
uint16_t receptionFlags;
messageCount = 0;
#if (CAN1_FIFO_STARTING_BUFFER<16)
/* Check any message in buffer 0 to buffer 15*/
receptionFlags = C1RXFUL1;
if (receptionFlags != 0)
{
/* check whether a message is received */
for (currentBuffer=0 ; currentBuffer < 16; currentBuffer++)
{
if (((receptionFlags >> currentBuffer ) & 0x1) == 0x1)
{
messageCount++;
}
}
}
#endif
/* Check any message in buffer 16 to buffer 32*/
receptionFlags = C1RXFUL2;
if (receptionFlags != 0)
{
/* check whether a message is received */
for (currentBuffer=0 ; currentBuffer < 16; currentBuffer++)
{
if (((receptionFlags >> currentBuffer ) & 0x1) == 0x1)
{
messageCount++;
}
}
}
return (messageCount);
}
/******************************************************************************
*
* Function: CAN1_sleep
* Description: Puts CAN1 module in disable mode.
*
******************************************************************************/
void CAN1_sleep(void)
{
C1INTFbits.WAKIF = 0;
C1INTEbits.WAKIE = 1;
/* put the module in disable mode */
C1CTRL1bits.REQOP = CAN_DISABLE_MODE;
while(C1CTRL1bits.OPMODE != CAN_DISABLE_MODE);
//Wake up from sleep should set the CAN1 module straight into Normal mode
}
/* Null weak implementations of callback functions. */
void __attribute__((weak)) CAN1_CallbackBusOff(void)
{
}
void __attribute__((weak)) CAN1_CallbackTxErrorPassive(void)
{
}
void __attribute__((weak)) CAN1_CallbackRxErrorPassive(void)
{
}
void __attribute__((weak)) CAN1_CallbackMessageReceived(void)
{
}
void __attribute__((weak)) CAN1_CallbackRxBufferOverflow()
{
}
/**
End of File
*/
I have tried to work with LIS3DSH sensor using SPI protocol. I applied procedures on STM32L0 Discovery kit LoRa. But it didn't work.
My problem is The LIS3DSH x-y-z-axis output value is invalid and the value is not changed. No matter which direction I rotate the device but I check ID of LIS3DSH is correct ( 0011 1111)
Component
STM32L0 Discovery kit LoRa
LIS3DSH (https://www.amazon.com/LIS3DSH-High-Resolution-Three-axis-Accelerometer-Triaxial/dp/B07QS5D9K9/ref=sr_1_4?dchild=1&keywords=LIS3DSH&qid=1615701212&sr=8-4)
init SPI2
...
void HW_SPI2_Init(void)
{
/*##-1- Configure the SPI2 peripheral */
/* Set the SPI parameters */
hspi2.Instance = SPI2;
hspi2.Init.BaudRatePrescaler = SpiFrequency(10000000);
hspi2.Init.Direction = SPI_DIRECTION_2LINES;
hspi2.Init.Mode = SPI_MODE_MASTER;
hspi2.Init.CLKPolarity = SPI_POLARITY_LOW; // CPOL = 0
hspi2.Init.CLKPhase = SPI_PHASE_2EDGE; // CPHA = 1
// hspi2.Init.CLKPhase = SPI_PHASE_1EDGE; // CPHA = 0
hspi2.Init.DataSize = SPI_DATASIZE_8BIT;
// hspi2.Init.DataSize = SPI_DATASIZE_16BIT;
hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi2.Init.NSS = SPI_NSS_SOFT;
hspi2.Init.TIMode = SPI_TIMODE_DISABLE;
hspi2.Init.CRCPolynomial = 10;
SPI2_CLK_ENABLE(); // Enable clock for SPI 2
if (HAL_SPI_Init(&hspi2) != HAL_OK)
{
/* Initialization Error */
Error_Handler();
}
/*##-2- Configure the SPI GPIOs */
HW_SPI2_IoInit();
}
...
initialization LIS3DSH
void HW_SPI2_IoInit(void)
{
GPIO_InitTypeDef initStruct = {0};
initStruct.Mode = GPIO_MODE_AF_PP;
initStruct.Pull = GPIO_PULLUP ;
initStruct.Speed = GPIO_SPEED_FAST;
initStruct.Alternate = SPI2_AF;
HW_GPIO_Init(LIS3DH_SCLK_PORT, LIS3DH_SCLK_PIN, &initStruct);
HW_GPIO_Init(LIS3DH_MISO_PORT, LIS3DH_MISO_PIN, &initStruct);
HW_GPIO_Init(LIS3DH_MOSI_PORT, LIS3DH_MOSI_PIN, &initStruct);
initStruct.Mode = GPIO_MODE_OUTPUT_PP;
initStruct.Pull = GPIO_NOPULL;
HW_GPIO_Init(LIS3DH_NSS_PORT, LIS3DH_NSS_PIN, &initStruct);
HW_GPIO_Write(LIS3DH_NSS_PORT, LIS3DH_NSS_PIN, 1);
}
CS ON or OFF
void HW_SPI2_CS_ON (void)
{
HW_GPIO_Write(LIS3DH_NSS_PORT, LIS3DH_NSS_PIN, 0);
}
void HW_SPI2_CS_OFF (void)
{
HW_GPIO_Write(LIS3DH_NSS_PORT, LIS3DH_NSS_PIN, 1);
}
Read ID
uint8_t LIS3DSH_DH_CHECK_ID (void)
{
uint8_t addr = LIS3Dx_WHO_AM_I_ADDR | LIS3Dx_READ;
HW_SPI2_CS_ON();
HW_SPI2_SPI_1byte_Write_and_Read(addr);
HW_SPI2_CS_OFF();
UsingTypeint_LIS3DSH_DH.ID = au8BufferRead_SPI2[0];
return UsingTypeint_LIS3DSH_DH.ID;
}
Read X axis ( only) (Incorrect)
void LIS3DSH_DH_GET_XYZ (void)
{
uint8_t addr = LIS3Dx_OUT_X_L_ADDR | LIS3Dx_READ ;
HW_SPI2_CS_ON();
HW_SPI2_SPI_1byte_Write_and_Read(addr);
HW_SPI2_CS_OFF();
addr = LIS3Dx_OUT_X_H_ADDR | LIS3Dx_READ ;
HW_SPI2_CS_ON();
HW_SPI2_SPI_1byte_Write_and_Read(addr);
HW_SPI2_CS_OFF();
}
HW_SPI2_1byte_Write_and_Read
bool HW_SPI2_SPI_1byte_Write_and_Read(uint8_t u8Address)
{
if(HAL_SPI_Transmit(&hspi2, (uint8_t *)&u8Address, 1, HAL_MAX_DELAY) == HAL_OK){
if(HAL_SPI_Receive(&hspi2, (uint8_t *)&au8BufferRead_SPI2[0], 1, HAL_MAX_DELAY) == HAL_OK){
return true;
}
}
return false;
}
Signal
output X L
output X H
Am not sure if you are using the state machine and register accesses of the LIS3DSH accurately.
As a reference see the register mapping in https://github.com/STMicroelectronics/stm32-lis3dsh/blob/main/lis3dsh.h (start at line 95) and the code in https://github.com/STMicroelectronics/stm32-lis3dsh/blob/main/lis3dsh.c
The function that actually writes and reads the SPI bus is void ACCELERO_IO_Write(uint8_t *pBuffer, uint8_t WriteAddr, uint16_t NumByteToWrite) and void ACCELERO_IO_Read(uint8_t *pBuffer, uint8_t ReadAddr, uint16_t NumByteToRead)
This is defined in https://documentation.help/STM32F4-Discovery-BSP/stm32f4__discovery_8c_source.html at lines 560 and 594
In void ACCELERO_IO_Write(uint8_t *pBuffer, uint8_t WriteAddr, uint16_t NumByteToWrite) the actual SPI write is done at lines 574 to 582
00574 SPIx_WriteRead(WriteAddr);
00577 while(NumByteToWrite >= 0x01)
00578 {
00579 SPIx_WriteRead(*pBuffer);
00580 NumByteToWrite--;
00581 pBuffer++;
00582 }
(as always with SPI first activate register, then write data...)
In SPIx_WriteRead(WriteAddr); the WriteAddr is taken from the register mapping in https://github.com/STMicroelectronics/stm32-lis3dsh/blob/main/lis3dsh.h, start at line 9
(the above code by STM for the LIS3DSH is nice work, this implementation is very clean and structured)
The datasheet of the LIS3DSH is in https://www.st.com/resource/en/datasheet/lis3dsh.pdf, the reference manual is far more detailed it is in https://www.st.com/resource/en/application_note/dm00026768-lis3dsh-3axis-digital-output-accelerometer-stmicroelectronics.pdf it also includes explanation of the state machines, that have to be configured before the device works
I am currently trying to send messages via both of my FDCAN transmitters on my Nucleo. But I am only able to transmit via FDCAN1 (classic master) and not via FDCAN 2 (classic slave).
The configuration setup is the same, only FDCAN1 starts sending , while FDCAN 2 gets a buffer overflow after a short time and never sends anything. I am monitoring with CANoe, where I can only see the message send via FDCAN1.
I also know it is not a hardware issue, since I changed my cables and the board and the problem remained the same. My cables are also terminated correctly...
Is there anything obvious I am missing?
Here is my code, I used CubeMx for the first initialisation.
The fdcan.c File:
`
FDCAN_HandleTypeDef hfdcan1;
FDCAN_HandleTypeDef hfdcan2;
/* FDCAN1 init function */
void MX_FDCAN1_Init(void)
{
hfdcan1.Instance = FDCAN1;
hfdcan1.Init.FrameFormat = FDCAN_FRAME_CLASSIC;
hfdcan1.Init.Mode = FDCAN_MODE_NORMAL;
hfdcan1.Init.AutoRetransmission = DISABLE;
hfdcan1.Init.TransmitPause = DISABLE;
hfdcan1.Init.NominalPrescaler = 5;
hfdcan1.Init.NominalSyncJumpWidth = 1;
hfdcan1.Init.NominalTimeSeg1 = 11;
hfdcan1.Init.NominalTimeSeg2 = 4;
hfdcan1.Init.DataPrescaler = 1;
hfdcan1.Init.DataSyncJumpWidth = 1;
hfdcan1.Init.DataTimeSeg1 = 1;
hfdcan1.Init.DataTimeSeg2 = 1;
hfdcan1.Init.MessageRAMOffset = 0;
hfdcan1.Init.StdFiltersNbr = 0;
hfdcan1.Init.ExtFiltersNbr = 0;
hfdcan1.Init.RxFifo0ElmtsNbr = 8;
hfdcan1.Init.RxFifo0ElmtSize = FDCAN_DATA_BYTES_8;
hfdcan1.Init.RxFifo1ElmtsNbr = 0;
hfdcan1.Init.RxFifo1ElmtSize = FDCAN_DATA_BYTES_8;
hfdcan1.Init.RxBuffersNbr = 0;
hfdcan1.Init.RxBufferSize = FDCAN_DATA_BYTES_8;
hfdcan1.Init.TxEventsNbr = 0;
hfdcan1.Init.TxBuffersNbr = 0;
hfdcan1.Init.TxFifoQueueElmtsNbr = 8;
hfdcan1.Init.TxFifoQueueMode = FDCAN_TX_FIFO_OPERATION;
hfdcan1.Init.TxElmtSize = FDCAN_DATA_BYTES_8;
hfdcan1.msgRam.StandardFilterSA = 0;
hfdcan1.msgRam.ExtendedFilterSA = 0;
hfdcan1.msgRam.RxFIFO0SA = 0;
hfdcan1.msgRam.RxFIFO1SA = 0;
hfdcan1.msgRam.RxBufferSA = 0;
hfdcan1.msgRam.TxEventFIFOSA = 0;
hfdcan1.msgRam.TxBufferSA = 0;
hfdcan1.msgRam.TxFIFOQSA = 0;
hfdcan1.msgRam.TTMemorySA = 0;
hfdcan1.msgRam.EndAddress = 0;
hfdcan1.ErrorCode = 0;
if (HAL_FDCAN_Init(&hfdcan1) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
}
/* FDCAN2 init function */
void MX_FDCAN2_Init(void)
{
hfdcan2.Instance = FDCAN2;
hfdcan2.Init.FrameFormat = FDCAN_FRAME_CLASSIC;
hfdcan2.Init.Mode = FDCAN_MODE_NORMAL;
hfdcan2.Init.AutoRetransmission = DISABLE;
hfdcan2.Init.TransmitPause = DISABLE;
hfdcan2.Init.NominalPrescaler = 5;
hfdcan2.Init.NominalSyncJumpWidth = 1;
hfdcan2.Init.NominalTimeSeg1 = 11;
hfdcan2.Init.NominalTimeSeg2 = 4;
hfdcan2.Init.DataPrescaler = 1;
hfdcan2.Init.DataSyncJumpWidth = 1;
hfdcan2.Init.DataTimeSeg1 = 1;
hfdcan2.Init.DataTimeSeg2 = 1;
hfdcan2.Init.MessageRAMOffset = 0;
hfdcan2.Init.StdFiltersNbr = 0;
hfdcan2.Init.ExtFiltersNbr = 0;
hfdcan2.Init.RxFifo0ElmtsNbr = 8;
hfdcan2.Init.RxFifo0ElmtSize = FDCAN_DATA_BYTES_8;
hfdcan2.Init.RxFifo1ElmtsNbr = 0;
hfdcan2.Init.RxFifo1ElmtSize = FDCAN_DATA_BYTES_8;
hfdcan2.Init.RxBuffersNbr = 0;
hfdcan2.Init.RxBufferSize = FDCAN_DATA_BYTES_8;
hfdcan2.Init.TxEventsNbr = 0;
hfdcan2.Init.TxBuffersNbr = 0;
hfdcan2.Init.TxFifoQueueElmtsNbr = 16;
hfdcan2.Init.TxFifoQueueMode = FDCAN_TX_FIFO_OPERATION;
hfdcan2.Init.TxElmtSize = FDCAN_DATA_BYTES_8;
hfdcan2.msgRam.StandardFilterSA = 0;
hfdcan2.msgRam.ExtendedFilterSA = 0;
hfdcan2.msgRam.RxFIFO0SA = 0;
hfdcan2.msgRam.RxFIFO1SA = 0;
hfdcan2.msgRam.RxBufferSA = 0;
hfdcan2.msgRam.TxEventFIFOSA = 0;
hfdcan2.msgRam.TxBufferSA = 0;
hfdcan2.msgRam.TxFIFOQSA = 0;
hfdcan2.msgRam.TTMemorySA = 0;
hfdcan2.msgRam.EndAddress = 0;
hfdcan2.ErrorCode = 0;
if (HAL_FDCAN_Init(&hfdcan2) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
}`
and the relevant part of the main.c:
uint8_t TxData[8] = {0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA};
uint8_t TxData2[8] = {0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAB};
uint32_t msgerror=0;
uint32_t msgerror1=0;
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_NVIC_Init(void);
/**
* #brief The application entry point.
*
* #retval None
*/
int main(void)
{
/* MCU Configuration----------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* Configure the system clock */
SystemClock_Config();
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_FDCAN1_Init();
MX_FDCAN2_Init();
/* Initialize interrupts */
MX_NVIC_Init();
/* USER CODE BEGIN 2 */
TxHeader.Identifier = 0x120;
TxHeader.IdType = FDCAN_STANDARD_ID;
TxHeader.TxFrameType = FDCAN_DATA_FRAME;
TxHeader.DataLength = FDCAN_DLC_BYTES_8;
TxHeader.ErrorStateIndicator = FDCAN_ESI_ACTIVE;
TxHeader.BitRateSwitch = FDCAN_BRS_OFF;
TxHeader.FDFormat = FDCAN_CLASSIC_CAN;
TxHeader.TxEventFifoControl = FDCAN_NO_TX_EVENTS;
TxHeader.MessageMarker = 0;
HAL_FDCAN_Start(&hfdcan1);
HAL_FDCAN_Start(&hfdcan2);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
if (HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan2, &TxHeader, TxData) != HAL_OK)
{
/* Transmission request Error */
msgerror++;
}
if (HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan1, &TxHeader, TxData2) != HAL_OK)
{
/* Transmission request Error */
msgerror1++;
}
HAL_Delay(100);
}
After finding the right data sheet, I found the solution. In the configuration for FDCAN2 I need to implement an offset:
hfdcan2.Init.MessageRAMOffset = sizeof(hfdcan1);
After implementing this change transmit and receive are working without problem.
I am using QSPI not to connect memory, but a FTDI display.
I used STM32CubeMX and Atollic TrueStudio. I included FreeRTOS, but I'm not using that, yet.
Using QuadSPI, I have trouble to read and write 1, 2 or 4 bytes, where I transmit a 3 byte memory address.
If I try to read an address like this, it times out at HAL_QSPI_Receive, and no signals are generated on the bus, if I configure
s_command.AddressMode = QSPI_ADDRESS_1_LINE;
If I configure
s_command.AddressMode = QSPI_ADDRESS_NONE;
Signals are generated to read a byte, but the address is not send of course.
To send the address and receive bytes afterwards, I send the address in the Alternate bytes. But now the number of bytes can 1 or 2, but not 4, because I will get a time-out again.
My code pieces
uint8_t pData[4];
uint32_t address = REG_ID;
QspiReadData(address, 1, pData);
uint32_t v = 0x12345678;
pData[0] = v >> 24;
pData[1] = (v >> 16) & 0xff;
pData[2] = (v >> 8) & 0xff;
pData[3] = v & 0xff;
QspiWriteData(addr, 4, pData);
uint8_t QspiReadData(uint32_t address, uint32_t size, uint8_t* pData)
{
QSPI_CommandTypeDef s_command;
QSPI_AutoPollingTypeDef s_config;
/* Initialize the read command */
s_command.InstructionMode = QSPI_INSTRUCTION_NONE;
s_command.Instruction = 0;
s_command.AddressMode = QSPI_ADDRESS_1_LINE;
s_command.AddressSize = QSPI_ADDRESS_32_BITS;
s_command.Address = address;
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
s_command.AlternateBytes = 0;
s_command.AlternateBytesSize = 0;
s_command.DataMode = QSPI_DATA_1_LINE; // QSPI_DATA_4_LINES
s_command.DummyCycles = 0;
s_command.NbData = size;
s_command.DdrMode = QSPI_DDR_MODE_DISABLE;
s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
/* Configure the command */
printf("HAL_QSPI_Command\n");
if (HAL_QSPI_Command(&hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
printf("HAL_ERROR\n");
return HAL_ERROR;
}
/* Reception of the data */
printf("HAL_QSPI_Receive\n");
if (HAL_QSPI_Receive(&hqspi, pData, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
printf("HAL_ERROR\n"); // Timeout after 5000mS
return HAL_ERROR;
}
return HAL_OK;
}
/* QUADSPI init function */
void MX_QUADSPI_Init(void)
{
hqspi.Instance = QUADSPI;
hqspi.Init.ClockPrescaler = 254; /* 4 QSPI Freq= 108 MHz / (1+4) = 21.6 MHz */
hqspi.Init.FifoThreshold = 1;
hqspi.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_NONE;
hqspi.Init.FlashSize = 0;
hqspi.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_8_CYCLE;
hqspi.Init.ClockMode = QSPI_CLOCK_MODE_0; // QSPI_CLOCK_MODE_0 Rising edge CPOL=0, QSPI_CLOCK_MODE_3 Falling edge CPOL=1
hqspi.Init.FlashID = QSPI_FLASH_ID_1;
hqspi.Init.DualFlash = QSPI_DUALFLASH_DISABLE;
if (HAL_QSPI_Init(&hqspi) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
}
uint8_t QspiWriteData(uint32_t address, uint32_t size, uint8_t* pData)
{
QSPI_CommandTypeDef s_command;
printf("Ft813QspiReadData8(%ld, %d, pData)\n", address, size);
/* Initialize the read command */
s_command.InstructionMode = QSPI_INSTRUCTION_NONE;
s_command.Instruction = 0;
s_command.AddressMode = QSPI_ADDRESS_NONE;
s_command.AddressSize = QSPI_ADDRESS_24_BITS;
s_command.Address = 0;
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_1_LINE;
s_command.AlternateBytes = address;
s_command.AlternateBytesSize = QSPI_ALTERNATE_BYTES_24_BITS;
s_command.DataMode = QSPI_DATA_1_LINE;
s_command.DummyCycles = 0;
s_command.NbData = size;
s_command.DdrMode = QSPI_DDR_MODE_DISABLE;
s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
/* Configure the command */
printf("HAL_QSPI_Command\n");
if (HAL_QSPI_Command(&hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
printf("HAL_ERROR\n");
return HAL_ERROR;
}
/* Reception of the data */
printf("HAL_QSPI_Transmit\n");
if (HAL_QSPI_Transmit(&hqspi, pData, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
printf("HAL_ERROR\n");
return HAL_ERROR;
}
return HAL_OK;
}
What can be the problem?
The GPIO pins were configured like this, in case it helps sombody else:
void HAL_QSPI_MspInit(QSPI_HandleTypeDef* qspiHandle)
{
GPIO_InitTypeDef GPIO_InitStruct;
if(qspiHandle->Instance==QUADSPI)
{
/* USER CODE BEGIN QUADSPI_MspInit 0 */
/* USER CODE END QUADSPI_MspInit 0 */
/* QUADSPI clock enable */
__HAL_RCC_QSPI_CLK_ENABLE();
/**QUADSPI GPIO Configuration
PF6 ------> QUADSPI_BK1_IO3
PF7 ------> QUADSPI_BK1_IO2
PF8 ------> QUADSPI_BK1_IO0
PF9 ------> QUADSPI_BK1_IO1
PF10 ------> QUADSPI_CLK
PB10 ------> QUADSPI_BK1_NCS
*/
GPIO_InitStruct.Pin = QUADSPI_BK1_IO3_Pin|QUADSPI_BK1_IO2_Pin|QUADSPI_CLK_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF9_QUADSPI;
HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);
GPIO_InitStruct.Pin = QUADSPI_BK1_IO0_Pin|QUADSPI_BK1_IO1_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF10_QUADSPI;
HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);
GPIO_InitStruct.Pin = QUADSPI_BK1_NCS_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF9_QUADSPI;
HAL_GPIO_Init(QUADSPI_BK1_NCS_GPIO_Port, &GPIO_InitStruct);
/* QUADSPI DMA Init */
/* QUADSPI Init */
hdma_quadspi.Instance = DMA2_Stream2;
hdma_quadspi.Init.Channel = DMA_CHANNEL_11;
hdma_quadspi.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_quadspi.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_quadspi.Init.MemInc = DMA_MINC_ENABLE;
hdma_quadspi.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_quadspi.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_quadspi.Init.Mode = DMA_NORMAL;
hdma_quadspi.Init.Priority = DMA_PRIORITY_LOW;
hdma_quadspi.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
if (HAL_DMA_Init(&hdma_quadspi) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
__HAL_LINKDMA(qspiHandle,hdma,hdma_quadspi);
/* QUADSPI interrupt Init */
HAL_NVIC_SetPriority(QUADSPI_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(QUADSPI_IRQn);
/* USER CODE BEGIN QUADSPI_MspInit 1 */
/* USER CODE END QUADSPI_MspInit 1 */
}
}
hqspi.Init.FlashSize = 0; is wrong. QuadSPI module needs to learn the memory of device which will write/read. Change it with 31. It will run.
I am trying to start learning programming and I am trying to get this code to work: https://github.com/espruino/Espruino/blob/master/targetlibs/stm32f4/lib/stm32f4xx_can.c
I am using Atollic TruStudio Lite.
I did the basic LED blinking code with Discovery, but other than that. I have no clue how to do this.
I don't get how am i supposed to simulate CAN message (and other things) via STM32.
I am a total beginner, so please, don't rip my throat out.
Thanks
Here's an example of a CAN loopback you can try. It's a CAN loopback test. It's in the stm32f4 examples that you can download from the STM website. This is for an STM32439 eval board but it should work on a discovery. (Both are STM32F4 chips).
#define USE_CAN1
/* Uncomment the line below if you will use the CAN 2 peripheral */
/* #define USE_CAN2 */
#ifdef USE_CAN1
#define CANx CAN1
#define CAN_CLK RCC_APB1Periph_CAN1
#else /* USE_CAN2 */
#define CANx CAN2
#define CAN_CLK (RCC_APB1Periph_CAN1 | RCC_APB1Periph_CAN2)
#endif /* USE_CAN1 */
typedef enum {FAILED = 0, PASSED = !FAILED} TestStatus;
__IO uint32_t ret = 0; /* for return of the interrupt handling */
volatile TestStatus TestRx;
TestStatus CAN_Polling(void);
int main(void) {
/*!< At this stage the microcontroller clock setting is already configured,
this is done through SystemInit() function which is called from startup
files (startup_stm32f40_41xxx.s/startup_stm32f427_437xx.s/startup_stm32f429_439xx.s)
before to branch to application main.
To reconfigure the default setting of SystemInit() function, refer to
system_stm32f4xx.c file
*/
/* CANx Periph clock enable */
RCC_APB1PeriphClockCmd(CAN_CLK, ENABLE);
/* Initialize LEDs mounted on EVAL board */
STM_EVAL_LEDInit(LED1);
STM_EVAL_LEDInit(LED2);
/* CAN transmit at 125Kb/s and receive by polling in loopback mode */
TestRx = CAN_Polling();
if (TestRx != FAILED) { /* OK */
/* Turn on LED1 */
STM_EVAL_LEDOn(LED1);
} else { /* KO */
/* Turn on LED2 */
STM_EVAL_LEDOn(LED2);
}
/* Infinite loop */
while (1) { }
}
/**
* #brief Configures the CAN, transmit and receive by polling
* #param None
* #retval PASSED if the reception is well done, FAILED in other case
*/
TestStatus CAN_Polling(void) {
CAN_InitTypeDef CAN_InitStructure;
CAN_FilterInitTypeDef CAN_FilterInitStructure;
CanTxMsg TxMessage;
CanRxMsg RxMessage;
uint32_t uwCounter = 0;
uint8_t TransmitMailbox = 0;
/* CAN register init */
CAN_DeInit(CANx);
/* CAN cell init */
CAN_InitStructure.CAN_TTCM = DISABLE;
CAN_InitStructure.CAN_ABOM = DISABLE;
CAN_InitStructure.CAN_AWUM = DISABLE;
CAN_InitStructure.CAN_NART = DISABLE;
CAN_InitStructure.CAN_RFLM = DISABLE;
CAN_InitStructure.CAN_TXFP = DISABLE;
CAN_InitStructure.CAN_Mode = CAN_Mode_LoopBack;
CAN_InitStructure.CAN_SJW = CAN_SJW_1tq;
/* CAN Baudrate = 175kbps (CAN clocked at 42 MHz) */
CAN_InitStructure.CAN_BS1 = CAN_BS1_6tq;
CAN_InitStructure.CAN_BS2 = CAN_BS2_8tq;
CAN_InitStructure.CAN_Prescaler = 16;
CAN_Init(CANx, &CAN_InitStructure);
/* CAN filter init */
#ifdef USE_CAN1
CAN_FilterInitStructure.CAN_FilterNumber = 0;
#else /* USE_CAN2 */
CAN_FilterInitStructure.CAN_FilterNumber = 14;
#endif /* USE_CAN1 */
CAN_FilterInitStructure.CAN_FilterMode = CAN_FilterMode_IdMask;
CAN_FilterInitStructure.CAN_FilterScale = CAN_FilterScale_32bit;
CAN_FilterInitStructure.CAN_FilterIdHigh = 0x0000;
CAN_FilterInitStructure.CAN_FilterIdLow = 0x0000;
CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0x0000;
CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0x0000;
CAN_FilterInitStructure.CAN_FilterFIFOAssignment = 0;
CAN_FilterInitStructure.CAN_FilterActivation = ENABLE;
CAN_FilterInit(&CAN_FilterInitStructure);
/* transmit */
TxMessage.StdId = 0x11;
TxMessage.RTR = CAN_RTR_DATA;
TxMessage.IDE = CAN_ID_STD;
TxMessage.DLC = 2;
TxMessage.Data[0] = 0xCA;
TxMessage.Data[1] = 0xFE;
TransmitMailbox = CAN_Transmit(CANx, &TxMessage);
uwCounter = 0;
while((CAN_TransmitStatus(CANx, TransmitMailbox) != CANTXOK) && (uwCounter != 0xFFFF)) {
uwCounter++;
}
uwCounter = 0;
while((CAN_MessagePending(CANx, CAN_FIFO0) < 1) && (uwCounter != 0xFFFF)) {
uwCounter++;
}
/* receive */
RxMessage.StdId = 0x00;
RxMessage.IDE = CAN_ID_STD;
RxMessage.DLC = 0;
RxMessage.Data[0] = 0x00;
RxMessage.Data[1] = 0x00;
CAN_Receive(CANx, CAN_FIFO0, &RxMessage);
if (RxMessage.StdId != 0x11) {
return FAILED;
}
if (RxMessage.IDE != CAN_ID_STD) {
return FAILED;
}
if (RxMessage.DLC != 2) {
return FAILED;
}
if ((RxMessage.Data[0]<<8|RxMessage.Data[1]) != 0xCAFE) {
return FAILED;
}
return PASSED; /* Test Passed */
}