CAN Bus with MCC Microchip - c
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
*/
Related
How to update the LED on a TI board and report to the server every second via UART
I am modifying a code in embedded C language and trying to make it to where it checks buttons every 200ms, checks the temperature every 500ms, and update the LED and report to the server every second. My code appears to be complete but when I run it, nothing outputs to the console, and my LED light neither turns off or on when I press either buttons on the side of the TI board. Is there something wrong with my nested while loop? Here is my code: /* * ======== gpiointerrupt.c ======== */ #include <stdint.h> #include <stddef.h> /* Driver Header files */ #include <ti/drivers/GPIO.h> #include <ti/drivers/I2C.h> #include <ti/drivers/UART.h> /* Driver configuration */ #include "ti_drivers_config.h" /* Driver timer */ #include <ti/drivers/Timer.h> #define TRUE 1 #define FALSE 0 #define NUMBER_OF_TASKS 3 #define GLOBAL_PERIOD 100 //milliseconds #define DISPLAY(x) UART_write(uart, &output, x); // UART Global Variables char output[64]; int bytesToSend; // Driver Handles - Global variables UART_Handle uart; // Init variables int buttonCheckTime = 0; int tempCheckTime = 0; int displayCheckTime = 0; int buttonCheckPeriod = 200; int tempCheckPeriod = 500; int displayCheckPeriod = 1000; int setpoint = 25; int heat = 0; int seconds = 0; int temperature = 0; int firstButtonWasPressed = FALSE; // It is initally false that the button was pressed int secondButtonWasPressed = FALSE; // It is initally false that the button was pressed int global_period = GLOBAL_PERIOD; // Global period to be used initTimer() void initUART(void) { UART_Params uartParams; // Init the driver UART_init(); // Configure the driver UART_Params_init(&uartParams); uartParams.writeDataMode = UART_DATA_BINARY; uartParams.readDataMode = UART_DATA_BINARY; uartParams.readReturnMode = UART_RETURN_FULL; uartParams.baudRate = 115200; // Open the driver uart = UART_open(CONFIG_UART_0, &uartParams); if (uart == NULL) { /* UART_open() failed */ while (1) ; } } // I2C Global Variables static const struct { uint8_t address; uint8_t resultReg; char *id; } sensors[3] = { { 0x48, 0x0000, "11X" }, { 0x49, 0x0000, "116" }, { 0x41, 0x0001, "006" } }; uint8_t txBuffer[1]; uint8_t rxBuffer[2]; I2C_Transaction i2cTransaction; // Driver Handles - Global variables I2C_Handle i2c; // Initialize the I2C peripheral // Make sure you call initUART() before calling this function. void initI2C(void) { int8_t i, found; I2C_Params i2cParams; DISPLAY(snprintf(output, 64, "Initializing I2C Driver - ")) // Init the driver I2C_init(); // Configure the driver I2C_Params_init(&i2cParams); i2cParams.bitRate = I2C_400kHz; // Open the driver i2c = I2C_open(CONFIG_I2C_0, &i2cParams); if (i2c == NULL) { DISPLAY(snprintf(output, 64, "Failed\n\r")) while (1) ; } DISPLAY(snprintf(output, 32, "Passed\n\r")) // Boards were shipped with different sensors. // Welcome to the world of embedded systems. // Try to determine which sensor we have. // Scan through the possible sensor addresses /* Common I2C transaction setup */ i2cTransaction.writeBuf = txBuffer; i2cTransaction.writeCount = 1; i2cTransaction.readBuf = rxBuffer; i2cTransaction.readCount = 0; found = false; for (i = 0; i < 3; ++i) { i2cTransaction.slaveAddress = sensors[i].address; txBuffer[0] = sensors[i].resultReg; DISPLAY(snprintf(output, 64, "Is this %s? ", sensors[i].id)) if (I2C_transfer(i2c, &i2cTransaction)) { DISPLAY(snprintf(output, 64, "Found\n\r")) found = true; break; } DISPLAY(snprintf(output, 64, "No\n\r")) } if (found) { DISPLAY(snprintf(output, 64, "Detected TMP%s I2C address: %x\n\r", sensors[i].id, i2cTransaction.slaveAddress)) } else { DISPLAY(snprintf(output, 64, "Temperature sensor not found, contact professor\n\r")) } } int16_t readTemp(void) { int j; int16_t temperature = 0; i2cTransaction.readCount = 2; if (I2C_transfer(i2c, &i2cTransaction)) { /* * Extract degrees C from the received data; * see TMP sensor datasheet */ temperature = (rxBuffer[0] << 8) | (rxBuffer[1]); temperature *= 0.0078125; /* * If the MSB is set '1', then we have a 2's complement * negative value which needs to be sign extended */ if (rxBuffer[0] & 0x80) { temperature |= 0xF000; } } else { DISPLAY(snprintf(output, 64, "Error reading temperature sensor (%d)\n\r", i2cTransaction.status)) DISPLAY(snprintf(output,64, "Please power cycle your board by unplugging USB and plugging back in.\n\r")) } return temperature; } // Driver Handles - Global variables Timer_Handle timer0; volatile unsigned char TimerFlag = 0; // A single task in the task list. struct task_entry { void (*f)(); // Function to call to perform the task int elapsed_time; // Amount of time since last triggered int period; // Period of the task in ms char triggered; // Whether or not the task was triggered }; // Forward declaration void task_one(); void task_two(); void task_three(); void task_one() { // Processing for task_one takes place /* Every 200ms, check button presses */ if (buttonCheckTime >= buttonCheckPeriod) // Button check time equals or exceeds period { if (firstButtonWasPressed == TRUE) // Button on one side raises setpoint (thermostat setting) by 1 { setpoint += 1; // Increment thermostat firstButtonWasPressed = FALSE; // Reset button to FALSE } if (secondButtonWasPressed == TRUE) // Button on the other side lowers setpoint (thermostat setting) by 1 { setpoint -= 1; // Decrement thermostat secondButtonWasPressed = FALSE; // Reset button to FALSE } } } void task_two() { // Processing for task_two takes place if (tempCheckTime >= tempCheckPeriod) // Temperature check time equals or exceeds period { temperature = readTemp(); if (temperature > setpoint) { GPIO_write(CONFIG_GPIO_LED_0, CONFIG_GPIO_LED_OFF); heat = 0; } else { GPIO_write(CONFIG_GPIO_LED_0, CONFIG_GPIO_LED_ON); heat = 1; } } } void task_three() { // Processing for task_three takes place if (displayCheckTime == displayCheckPeriod) { DISPLAY(snprintf(output, 64, "<%02d,%02d,%d,%04d>\n\r", temperature, setpoint, heat, seconds)); ++seconds; } } // The task list struct task_entry tasks[NUMBER_OF_TASKS] = { { FALSE, &task_one, 500, 500 }, {FALSE, &task_two, 1500, 1500 }, { FALSE, &task_three, 2000, 2000 } }; void timerCallback(Timer_Handle myHandle, int_fast16_t status) { int x = 0; // Walk through each task. for (x = 0; x < NUMBER_OF_TASKS; x++) { // Check if task's interval has expire if (tasks[x].elapsed_time >= tasks[x].period) { // Bing! This task's timer is up // Set it's flag, and the global flag tasks[x].triggered = TRUE; TimerFlag = TRUE; // Reset the elapsed_time tasks[x].elapsed_time = 0; } else { tasks[x].elapsed_time += global_period; } } } void initTimer(void) { Timer_Params params; // Init the driver Timer_init(); // Configure the driver Timer_Params_init(¶ms); params.period = 1000000; params.periodUnits = Timer_PERIOD_US; params.timerMode = Timer_CONTINUOUS_CALLBACK; params.timerCallback = timerCallback; // Open the driver timer0 = Timer_open(CONFIG_TIMER_0, ¶ms); if (timer0 == NULL) { /* Failed to initialized timer */ while (1) { } } if (Timer_start(timer0) == Timer_STATUS_ERROR) { /* Failed to start timer */ while (1) { } } } /* * ======== gpioButtonFxn0 ======== * Callback function for the GPIO interrupt on CONFIG_GPIO_BUTTON_0. * * Note: GPIO interrupts are cleared prior to invoking callbacks. */ void gpioButtonFxn0(uint_least8_t index) { /* Toggle an LED */ //GPIO_toggle(CONFIG_GPIO_LED_0); firstButtonWasPressed = TRUE; // It is true that the button was pressed } /* * ======== gpioButtonFxn1 ======== * Callback function for the GPIO interrupt on CONFIG_GPIO_BUTTON_1. * This may not be used for all boards. * * Note: GPIO interrupts are cleared prior to invoking callbacks. */ void gpioButtonFxn1(uint_least8_t index) { /* Toggle an LED */ //GPIO_toggle(CONFIG_GPIO_LED_1); secondButtonWasPressed = TRUE; } /* * ======== mainThread ======== */ void* mainThread(void *arg0) { /* Call driver init functions */ GPIO_init(); /* Configure the LED and button pins */ GPIO_setConfig(CONFIG_GPIO_LED_0, GPIO_CFG_OUT_STD | GPIO_CFG_OUT_LOW); //GPIO_setConfig(CONFIG_GPIO_BUTTON_0; //GPIO_CFG_IN_PU | GPIO_CFG_IN_INT_FALLING); /* Turn on user LED */ GPIO_write(CONFIG_GPIO_LED_0, CONFIG_GPIO_LED_ON); /* Install Button callback */ GPIO_setCallback(CONFIG_GPIO_BUTTON_0, gpioButtonFxn0); /* Enable interrupts */ GPIO_enableInt(CONFIG_GPIO_BUTTON_0); /* * If more than one input pin is available for your device, interrupts * will be enabled on CONFIG_GPIO_BUTTON1. */ if (CONFIG_GPIO_BUTTON_0 != CONFIG_GPIO_BUTTON_1) { /* Configure BUTTON1 pin */ GPIO_setConfig(CONFIG_GPIO_BUTTON_1, GPIO_CFG_IN_PU | GPIO_CFG_IN_INT_FALLING); /* Install Button callback */ GPIO_setCallback(CONFIG_GPIO_BUTTON_1, gpioButtonFxn1); /* Enable interrupts */ GPIO_enableInt(CONFIG_GPIO_BUTTON_1); } // Call driver init functions initUART(); // The UART must be initialized before calling initI2C() initI2C(); initTimer(); // Loop Forever while (TRUE) { readTemp(); // Every 200ms check the button flags task_one(); // Every 500ms read the temperature and update the LED task_two(); // Every second output the following to the UART // "<%02d,%02d,%d,%04d>, temperature, setpoint, heat, seconds task_three(); // Wait for task intervals (periods) to elapse while (!TimerFlag) { } // Wait for timer period // Process the tasks for which the interval has expired int x = 0; for (x = 0; x < NUMBER_OF_TASKS; x++) { if (tasks[x].triggered) { tasks[x].f(); // reset tasks[x].triggered = FALSE; } } // Reset everything (e.g. flags) and go back to the beginning TimerFlag = FALSE; // Lower flag raised by timer ++global_period; } }
How can I use esp-idf-mirf nRF24L01/Si24R1 driver to transmit audio sampled with i2s_read?
Original post - 12/2022 I'm currently trying to transmit audio via nRF24 with an ESP32 development board using a driver library from nopnop2002. I'm using the i2s-adc lib functions to get data from an analog microphone and save it into a buffer after scaling it down to 8-bit so that the other esp32 can play it directly with its DAC converter. At first, I had a large i2s_read_len and later I suspected that this could be an issue so I decided to reduce it to 12-bit (the ADC bit width of the esp32) for testing purposes. What is the ideal size for my audio packets? I'm also not sure how to handle the sampling rate of i2s_read and the rate at which I attempt to send data to the nRF24 via SPI. As far as I know the internal ADC-I2S already has a queue implemented, should I make another one and use vTaskDelay(??? / portTICK_PERIOD_MS); to avoid sending data too fast? Here's what I currently have ignoring the includes: #define V_REF 1100 #define I2S_COMM_MODE 0 // ADC/DAC Mode #define I2S_SAMPLE_RATE 44100 #define I2S_SAMPLE_BITS 16 #define I2S_BUF_DEBUG 0 // enable display buffer for debug #define I2S_READ_LEN 16 * 1024 // I2S read buffer length #define I2S_FORMAT (I2S_CHANNEL_FMT_ONLY_RIGHT) #define I2S_CHANNEL_NUM 0 // I2S channel number #define I2S_ADC_UNIT ADC_UNIT_1 // I2S built-in ADC unit #define I2S_ADC_CHANNEL ADC1_CHANNEL_0 // I2S built-in ADC channel GPIO36 #define BIT_SAMPLE 16 #define SPI_DMA_CHAN SPI_DMA_CH_AUTO #define NUM_CHANNELS 1 // For mono recording only! #define SAMPLE_SIZE (BIT_SAMPLE * 1024) #define BYTE_RATE (I2S_SAMPLE_RATE * (BIT_SAMPLE / 8)) * NUM_CHANNELS /** * #brief I2S ADC mode init. */ void init_microphone(void) { int i2s_num = I2S_COMM_MODE; i2s_config_t i2s_config = { .mode = I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN | I2S_MODE_ADC_BUILT_IN, .sample_rate = I2S_SAMPLE_RATE, .bits_per_sample = I2S_SAMPLE_BITS, .communication_format = I2S_COMM_FORMAT_STAND_MSB, .channel_format = I2S_FORMAT, .intr_alloc_flags = 0, .dma_buf_count = 6, .dma_buf_len = 256, .use_apll = 1, }; // Call driver installation function and adc pad. ESP_ERROR_CHECK(i2s_driver_install(i2s_num, &i2s_config, 0, NULL)); ESP_ERROR_CHECK(i2s_set_adc_mode(I2S_ADC_UNIT, I2S_ADC_CHANNEL)); } /** * #brief Scale data to 8bit for data from ADC. * Data from ADC are 12bit width by default. * #param d_buff: destination buffer * #param s_buff: source buffer * #param len: length of source buffer */ void i2s_adc_data_scale(uint8_t *d_buff, uint8_t *s_buff, uint32_t len) { uint32_t j = 0; uint32_t dac_value = 0; #if (EXAMPLE_I2S_SAMPLE_BITS == 16) for (int i = 0; i < len; i += 2) { dac_value = ((((uint16_t)(s_buff[i + 1] & 0xf) << 8) | ((s_buff[i + 0])))); d_buff[j++] = 0; d_buff[j++] = dac_value * 256 / 4096; } #else for (int i = 0; i < len; i += 4) { dac_value = ((((uint16_t)(s_buff[i + 3] & 0xf) << 8) | ((s_buff[i + 2])))); d_buff[j++] = 0; d_buff[j++] = 0; d_buff[j++] = 0; d_buff[j++] = dac_value * 256 / 4096; } #endif } #if CONFIG_TRANSMITTER void transmitter(void *pvParameters) { size_t bytes_read; ESP_LOGI(pcTaskGetName(0), "Start"); int i2s_read_len = (12); char *i2s_read_buff = (char *)calloc(i2s_read_len, sizeof(char)); uint8_t *i2s_write_buff = (uint8_t *)calloc(i2s_read_len, sizeof(char)); i2s_adc_enable(I2S_CHANNEL_NUM); NRF24_t dev; Nrf24_init(&dev); uint8_t payload = sizeof(i2s_read_buff); uint8_t channel = 90; Nrf24_config(&dev, channel, payload); // Set the receiver address using 5 characters esp_err_t ret = Nrf24_setTADDR(&dev, (uint8_t *)"FGHIJ"); if (ret != ESP_OK) { ESP_LOGE(pcTaskGetName(0), "nrf24l01 not installed"); while (1) { vTaskDelay(1); } } #if CONFIG_ADVANCED AdvancedSettings(&dev); #endif // CONFIG_ADVANCED // Print settings Nrf24_printDetails(&dev); // Start ADC while (1) { // Read data from I2S bus, in this case, from ADC. // i2s_read(I2S_CHANNEL_NUM, (void *)i2s_read_buff, i2s_read_len, &bytes_read, portMAX_DELAY); // process data and scale to 8bit for I2S DAC. i2s_adc_data_scale(i2s_write_buff, (uint8_t *)i2s_read_buff, i2s_read_len); // i2s_write_buff needs to be the buffer that is sent via nr24l01. Nrf24_send(&dev, i2s_write_buff); if (Nrf24_isSend(&dev, 1000)) { ESP_LOGI(pcTaskGetName(0), "sending audio data ..."); } else { ESP_LOGW(pcTaskGetName(0), "sending failed ..."); } } } #endif // CONFIG_TRANSMITTER void app_main(void) { // I2S ADC mode microphone init. init_microphone(); #if CONFIG_TRANSMITTER xTaskCreate(transmitter, "TRANSMITTER", 1024 * 3, NULL, 2, NULL); #endif // Stop I2S driver and destroy // ESP_ERROR_CHECK(i2s_driver_uninstall(I2S_COMM_MODE)); } Here is the code where Nrf24_send is defined: #include <string.h> #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include <driver/spi_master.h> #include <driver/gpio.h> #include "esp_log.h" #include "mirf.h" #define TAG "NRF24" // SPI Stuff #if CONFIG_SPI2_HOST #define HOST_ID SPI2_HOST #elif CONFIG_SPI3_HOST #define HOST_ID SPI3_HOST #endif static const int SPI_Frequency = 4000000; // Stable even with a long jumper cable //static const int SPI_Frequency = 6000000; //static const int SPI_Frequency = 8000000; // Requires a short jumper cable //static const int SPI_Frequency = 10000000; // Unstable even with a short jumper cable const char rf24_datarates[][8] = {"1Mbps", "2Mbps", "250Kbps"}; const char rf24_crclength[][10] = {"Disabled", "8 bits", "16 bits"}; const char rf24_pa_dbm[][8] = {"PA_MIN", "PA_LOW", "PA_HIGH", "PA_MAX"}; void Nrf24_init(NRF24_t * dev) { esp_err_t ret; ESP_LOGI(TAG, "CONFIG_MISO_GPIO=%d", CONFIG_MISO_GPIO); ESP_LOGI(TAG, "CONFIG_MOSI_GPIO=%d", CONFIG_MOSI_GPIO); ESP_LOGI(TAG, "CONFIG_SCLK_GPIO=%d", CONFIG_SCLK_GPIO); ESP_LOGI(TAG, "CONFIG_CE_GPIO=%d", CONFIG_CE_GPIO); ESP_LOGI(TAG, "CONFIG_CSN_GPIO=%d", CONFIG_CSN_GPIO); //gpio_pad_select_gpio(CONFIG_CE_GPIO); gpio_reset_pin(CONFIG_CE_GPIO); gpio_set_direction(CONFIG_CE_GPIO, GPIO_MODE_OUTPUT); gpio_set_level(CONFIG_CE_GPIO, 0); //gpio_pad_select_gpio(CONFIG_CSN_GPIO); gpio_reset_pin(CONFIG_CSN_GPIO); gpio_set_direction(CONFIG_CSN_GPIO, GPIO_MODE_OUTPUT); gpio_set_level(CONFIG_CSN_GPIO, 1); spi_bus_config_t spi_bus_config = { .sclk_io_num = CONFIG_SCLK_GPIO, .mosi_io_num = CONFIG_MOSI_GPIO, .miso_io_num = CONFIG_MISO_GPIO, .quadwp_io_num = -1, .quadhd_io_num = -1 }; ret = spi_bus_initialize( HOST_ID, &spi_bus_config, SPI_DMA_CH_AUTO ); ESP_LOGI(TAG, "spi_bus_initialize=%d",ret); assert(ret==ESP_OK); spi_device_interface_config_t devcfg; memset( &devcfg, 0, sizeof( spi_device_interface_config_t ) ); devcfg.clock_speed_hz = SPI_Frequency; // It does not work with hardware CS control. //devcfg.spics_io_num = csn_pin; // It does work with software CS control. devcfg.spics_io_num = -1; devcfg.queue_size = 7; devcfg.mode = 0; devcfg.flags = SPI_DEVICE_NO_DUMMY; spi_device_handle_t handle; ret = spi_bus_add_device( HOST_ID, &devcfg, &handle); ESP_LOGI(TAG, "spi_bus_add_device=%d",ret); assert(ret==ESP_OK); dev->cePin = CONFIG_CE_GPIO; dev->csnPin = CONFIG_CSN_GPIO; dev->channel = 1; dev->payload = 16; dev->_SPIHandle = handle; } bool spi_write_byte(NRF24_t * dev, uint8_t* Dataout, size_t DataLength ) { spi_transaction_t SPITransaction; if ( DataLength > 0 ) { memset( &SPITransaction, 0, sizeof( spi_transaction_t ) ); SPITransaction.length = DataLength * 8; SPITransaction.tx_buffer = Dataout; SPITransaction.rx_buffer = NULL; spi_device_transmit( dev->_SPIHandle, &SPITransaction ); } return true; } bool spi_read_byte(NRF24_t * dev, uint8_t* Datain, uint8_t* Dataout, size_t DataLength ) { spi_transaction_t SPITransaction; if ( DataLength > 0 ) { memset( &SPITransaction, 0, sizeof( spi_transaction_t ) ); SPITransaction.length = DataLength * 8; SPITransaction.tx_buffer = Dataout; SPITransaction.rx_buffer = Datain; spi_device_transmit( dev->_SPIHandle, &SPITransaction ); } return true; } uint8_t spi_transfer(NRF24_t * dev, uint8_t address) { uint8_t datain[1]; uint8_t dataout[1]; dataout[0] = address; //spi_write_byte(dev, dataout, 1 ); spi_read_byte(dev, datain, dataout, 1 ); return datain[0]; } void spi_csnHi(NRF24_t * dev) { gpio_set_level( dev->csnPin, 1 ); } void spi_csnLow(NRF24_t * dev) { gpio_set_level( dev->csnPin, 0 ); } // Sets the important registers in the MiRF module and powers the module // in receiving mode // NB: channel and payload must be set now. void Nrf24_config(NRF24_t * dev, uint8_t channel, uint8_t payload) { dev->channel = channel; dev->payload = payload; Nrf24_configRegister(dev, RF_CH, dev->channel); // Set RF channel Nrf24_configRegister(dev, RX_PW_P0, dev->payload); // Set length of incoming payload Nrf24_configRegister(dev, RX_PW_P1, dev->payload); Nrf24_powerUpRx(dev); // Start receiver Nrf24_flushRx(dev); } // Sets the receiving device address //void Nrf24_setRADDR(NRF24_t * dev, uint8_t * adr) esp_err_t Nrf24_setRADDR(NRF24_t * dev, uint8_t * adr) { esp_err_t ret = ESP_OK; Nrf24_writeRegister(dev, RX_ADDR_P1, adr, mirf_ADDR_LEN); uint8_t buffer[5]; Nrf24_readRegister(dev, RX_ADDR_P1, buffer, sizeof(buffer)); for (int i=0;i<5;i++) { ESP_LOGD(TAG, "adr[%d]=0x%x buffer[%d]=0x%x", i, adr[i], i, buffer[i]); if (adr[i] != buffer[i]) ret = ESP_FAIL; } return ret; } // Sets the transmitting device address //void Nrf24_setTADDR(NRF24_t * dev, uint8_t * adr) esp_err_t Nrf24_setTADDR(NRF24_t * dev, uint8_t * adr) { esp_err_t ret = ESP_OK; Nrf24_writeRegister(dev, RX_ADDR_P0, adr, mirf_ADDR_LEN); //RX_ADDR_P0 must be set to the sending addr for auto ack to work. Nrf24_writeRegister(dev, TX_ADDR, adr, mirf_ADDR_LEN); uint8_t buffer[5]; Nrf24_readRegister(dev, RX_ADDR_P0, buffer, sizeof(buffer)); for (int i=0;i<5;i++) { ESP_LOGD(TAG, "adr[%d]=0x%x buffer[%d]=0x%x", i, adr[i], i, buffer[i]); if (adr[i] != buffer[i]) ret = ESP_FAIL; } return ret; } // Add the receiving device address void Nrf24_addRADDR(NRF24_t * dev, uint8_t pipe, uint8_t adr) { uint8_t value; Nrf24_readRegister(dev, EN_RXADDR, &value, 1); if (pipe == 2) { Nrf24_configRegister(dev, RX_PW_P2, dev->payload); Nrf24_configRegister(dev, RX_ADDR_P2, adr); value = value | 0x04; Nrf24_configRegister(dev, EN_RXADDR, value); } else if (pipe == 3) { Nrf24_configRegister(dev, RX_PW_P3, dev->payload); Nrf24_configRegister(dev, RX_ADDR_P3, adr); value = value | 0x08; Nrf24_configRegister(dev, EN_RXADDR, value); } else if (pipe == 4) { Nrf24_configRegister(dev, RX_PW_P4, dev->payload); Nrf24_configRegister(dev, RX_ADDR_P4, adr); value = value | 0x10; Nrf24_configRegister(dev, EN_RXADDR, value); } else if (pipe == 5) { Nrf24_configRegister(dev, RX_PW_P5, dev->payload); Nrf24_configRegister(dev, RX_ADDR_P5, adr); value = value | 0x20; Nrf24_configRegister(dev, EN_RXADDR, value); } } // Checks if data is available for reading extern bool Nrf24_dataReady(NRF24_t * dev) { // See note in getData() function - just checking RX_DR isn't good enough uint8_t status = Nrf24_getStatus(dev); if ( status & (1 << RX_DR) ) return 1; // We can short circuit on RX_DR, but if it's not set, we still need // to check the FIFO for any pending packets //return !Nrf24_rxFifoEmpty(dev); return 0; } // Get pipe number for reading uint8_t Nrf24_getDataPipe(NRF24_t * dev) { uint8_t status = Nrf24_getStatus(dev); return ((status & 0x0E) >> 1); } extern bool Nrf24_rxFifoEmpty(NRF24_t * dev) { uint8_t fifoStatus; Nrf24_readRegister(dev, FIFO_STATUS, &fifoStatus, sizeof(fifoStatus)); return (fifoStatus & (1 << RX_EMPTY)); } // Reads payload bytes into data array extern void Nrf24_getData(NRF24_t * dev, uint8_t * data) { spi_csnLow(dev); // Pull down chip select spi_transfer(dev, R_RX_PAYLOAD ); // Send cmd to read rx payload spi_read_byte(dev, data, data, dev->payload); // Read payload spi_csnHi(dev); // Pull up chip select // NVI: per product spec, p 67, note c: // "The RX_DR IRQ is asserted by a new packet arrival event. The procedure // for handling this interrupt should be: 1) read payload through SPI, // 2) clear RX_DR IRQ, 3) read FIFO_STATUS to check if there are more // payloads available in RX FIFO, 4) if there are more data in RX FIFO, // repeat from step 1)." // So if we're going to clear RX_DR here, we need to check the RX FIFO // in the dataReady() function Nrf24_configRegister(dev, STATUS, (1 << RX_DR)); // Reset status register } // Clocks only one byte into the given MiRF register void Nrf24_configRegister(NRF24_t * dev, uint8_t reg, uint8_t value) { spi_csnLow(dev); spi_transfer(dev, W_REGISTER | (REGISTER_MASK & reg)); spi_transfer(dev, value); spi_csnHi(dev); } // Reads an array of bytes from the given start position in the MiRF registers void Nrf24_readRegister(NRF24_t * dev, uint8_t reg, uint8_t * value, uint8_t len) { spi_csnLow(dev); spi_transfer(dev, R_REGISTER | (REGISTER_MASK & reg)); spi_read_byte(dev, value, value, len); spi_csnHi(dev); } // Writes an array of bytes into inte the MiRF registers void Nrf24_writeRegister(NRF24_t * dev, uint8_t reg, uint8_t * value, uint8_t len) { spi_csnLow(dev); spi_transfer(dev, W_REGISTER | (REGISTER_MASK & reg)); spi_write_byte(dev, value, len); spi_csnHi(dev); } // Sends a data package to the default address. Be sure to send the correct // amount of bytes as configured as payload on the receiver. void Nrf24_send(NRF24_t * dev, uint8_t * value) { uint8_t status; status = Nrf24_getStatus(dev); while (dev->PTX) // Wait until last paket is send { status = Nrf24_getStatus(dev); if ((status & ((1 << TX_DS) | (1 << MAX_RT)))) { dev->PTX = 0; break; } } Nrf24_ceLow(dev); Nrf24_powerUpTx(dev); // Set to transmitter mode , Power up spi_csnLow(dev); // Pull down chip select spi_transfer(dev, FLUSH_TX ); // Write cmd to flush tx fifo spi_csnHi(dev); // Pull up chip select spi_csnLow(dev); // Pull down chip select spi_transfer(dev, W_TX_PAYLOAD ); // Write cmd to write payload spi_write_byte(dev, value, dev->payload); // Write payload spi_csnHi(dev); // Pull up chip select Nrf24_ceHi(dev); // Start transmission } // Test if chip is still sending. // When sending has finished return chip to listening. bool Nrf24_isSending(NRF24_t * dev) { uint8_t status; if (dev->PTX) { status = Nrf24_getStatus(dev); if ((status & ((1 << TX_DS) | (1 << MAX_RT)))) {// if sending successful (TX_DS) or max retries exceded (MAX_RT). Nrf24_powerUpRx(dev); return false; } return true; } return false; } // Test if Sending has finished or retry is over. // When sending has finished return trur. // When reach maximum number of TX retries return false. bool Nrf24_isSend(NRF24_t * dev, int timeout) { uint8_t status; TickType_t startTick = xTaskGetTickCount(); if (dev->PTX) { while(1) { status = Nrf24_getStatus(dev); /* if sending successful (TX_DS) or max retries exceded (MAX_RT). */ if (status & (1 << TX_DS)) { // Data Sent TX FIFO interrup Nrf24_powerUpRx(dev); return true; } if (status & (1 << MAX_RT)) { // Maximum number of TX retries interrupt ESP_LOGW(TAG, "Maximum number of TX retries interrupt"); Nrf24_powerUpRx(dev); return false; } // I believe either TX_DS or MAX_RT will always be notified. // Therefore, it is unusual for neither to be notified for a period of time. // I don't know exactly how to respond. TickType_t diffTick = xTaskGetTickCount() - startTick; if ( (diffTick * portTICK_PERIOD_MS) > timeout) { ESP_LOGE(TAG, "Status register timeout. status=0x%x", status); return false; } vTaskDelay(1); } } return false; } uint8_t Nrf24_getStatus(NRF24_t * dev) { uint8_t rv; Nrf24_readRegister(dev, STATUS, &rv, 1); return rv; } void Nrf24_powerUpRx(NRF24_t * dev) { dev->PTX = 0; Nrf24_ceLow(dev); Nrf24_configRegister(dev, CONFIG, mirf_CONFIG | ( (1 << PWR_UP) | (1 << PRIM_RX) ) ); //set device as TX mode Nrf24_ceHi(dev); Nrf24_configRegister(dev, STATUS, (1 << TX_DS) | (1 << MAX_RT)); //Clear seeded interrupt and max tx number interrupt } void Nrf24_flushRx(NRF24_t * dev) { spi_csnLow(dev); spi_transfer(dev, FLUSH_RX ); spi_csnHi(dev); } void Nrf24_powerUpTx(NRF24_t * dev) { dev->PTX = 1; Nrf24_configRegister(dev, CONFIG, mirf_CONFIG | ( (1 << PWR_UP) | (0 << PRIM_RX) ) ); } void Nrf24_ceHi(NRF24_t * dev) { gpio_set_level( dev->cePin, 1 ); } void Nrf24_ceLow(NRF24_t * dev) { gpio_set_level( dev->cePin, 0 ); } void Nrf24_powerDown(NRF24_t * dev) { Nrf24_ceLow(dev); Nrf24_configRegister(dev, CONFIG, mirf_CONFIG ); } //Set tx power : 0=-18dBm,1=-12dBm,2=-6dBm,3=0dBm void Nrf24_SetOutputRF_PWR(NRF24_t * dev, uint8_t val) { if (val > 3) return; uint8_t value; Nrf24_readRegister(dev, RF_SETUP, &value, 1); value = value & 0xF9; value = value | (val<< RF_PWR); //Nrf24_configRegister(dev, RF_SETUP, (val<< RF_PWR) ); Nrf24_configRegister(dev, RF_SETUP, value); } //Select between the high speed data rates:0=1Mbps, 1=2Mbps, 2=250Kbps void Nrf24_SetSpeedDataRates(NRF24_t * dev, uint8_t val) { if (val > 2) return; uint8_t value; Nrf24_readRegister(dev, RF_SETUP, &value, 1); if(val == 2) { value = value | 0x20; value = value & 0xF7; //Nrf24_configRegister(dev, RF_SETUP, (1 << RF_DR_LOW) ); Nrf24_configRegister(dev, RF_SETUP, value); } else { value = value & 0xD7; value = value | (val << RF_DR_HIGH); //Nrf24_configRegister(dev, RF_SETUP, (val << RF_DR_HIGH) ); Nrf24_configRegister(dev, RF_SETUP, value); } } //Set Auto Retransmit Delay 0=250us, 1=500us, ... 15=4000us void Nrf24_setRetransmitDelay(NRF24_t * dev, uint8_t val) { uint8_t value; Nrf24_readRegister(dev, SETUP_RETR, &value, 1); value = value & 0x0F; value = value | (val << ARD); Nrf24_configRegister(dev, SETUP_RETR, value); } void Nrf24_printDetails(NRF24_t * dev) { printf("================ SPI Configuration ================\n" ); printf("CSN Pin \t = GPIO%d\n",dev->csnPin); printf("CE Pin \t = GPIO%d\n", dev->cePin); printf("Clock Speed\t = %d\n", SPI_Frequency); printf("================ NRF Configuration ================\n"); Nrf24_print_status(Nrf24_getStatus(dev)); Nrf24_print_address_register(dev, "RX_ADDR_P0-1", RX_ADDR_P0, 2); Nrf24_print_byte_register(dev, "RX_ADDR_P2-5", RX_ADDR_P2, 4); Nrf24_print_address_register(dev, "TX_ADDR\t", TX_ADDR, 1); Nrf24_print_byte_register(dev, "RX_PW_P0-6", RX_PW_P0, 6); Nrf24_print_byte_register(dev, "EN_AA\t", EN_AA, 1); Nrf24_print_byte_register(dev, "EN_RXADDR", EN_RXADDR, 1); Nrf24_print_byte_register(dev, "RF_CH\t", RF_CH, 1); Nrf24_print_byte_register(dev, "RF_SETUP", RF_SETUP, 1); Nrf24_print_byte_register(dev, "CONFIG\t", CONFIG, 1); Nrf24_print_byte_register(dev, "DYNPD/FEATURE", DYNPD, 2); //printf("getDataRate()=%d\n",Nrf24_getDataRate(dev)); printf("Data Rate\t = %s\n",rf24_datarates[Nrf24_getDataRate(dev)]); #if 0 printf_P(PSTR("Model\t\t = " PRIPSTR "\r\n"),pgm_read_ptr(&rf24_model_e_str_P[isPVariant()])); #endif //printf("getCRCLength()=%d\n",Nrf24_getCRCLength(dev)); printf("CRC Length\t = %s\n", rf24_crclength[Nrf24_getCRCLength(dev)]); //printf("getPALevel()=%d\n",Nrf24_getPALevel(dev)); printf("PA Power\t = %s\n", rf24_pa_dbm[Nrf24_getPALevel(dev)]); uint8_t retransmit = Nrf24_getRetransmitDelay(dev); int16_t delay = (retransmit+1)*250; printf("Retransmit\t = %d us\n", delay); } #define _BV(x) (1<<(x)) void Nrf24_print_status(uint8_t status) { printf("STATUS\t\t = 0x%02x RX_DR=%x TX_DS=%x MAX_RT=%x RX_P_NO=%x TX_FULL=%x\r\n", status, (status & _BV(RX_DR)) ? 1 : 0, (status & _BV(TX_DS)) ? 1 : 0, (status & _BV(MAX_RT)) ? 1 : 0, ((status >> RX_P_NO) & 0x07), (status & _BV(TX_FULL)) ? 1 : 0); } void Nrf24_print_address_register(NRF24_t * dev, const char* name, uint8_t reg, uint8_t qty) { printf("%s\t =",name); while (qty--) { //uint8_t buffer[addr_width]; uint8_t buffer[5]; Nrf24_readRegister(dev, reg++, buffer, sizeof(buffer)); printf(" 0x"); #if 0 uint8_t* bufptr = buffer + sizeof buffer; while (--bufptr >= buffer) { printf("%02x", *bufptr); } #endif for(int i=0;i<5;i++) { printf("%02x", buffer[i]); } } printf("\r\n"); } void Nrf24_print_byte_register(NRF24_t * dev, const char* name, uint8_t reg, uint8_t qty) { printf("%s\t =", name); while (qty--) { uint8_t buffer[1]; Nrf24_readRegister(dev, reg++, buffer, 1); printf(" 0x%02x", buffer[0]); } printf("\r\n"); } uint8_t Nrf24_getDataRate(NRF24_t * dev) { rf24_datarate_e result; uint8_t dr; Nrf24_readRegister(dev, RF_SETUP, &dr, sizeof(dr)); //printf("RF_SETUP=%x\n",dr); dr = dr & (_BV(RF_DR_LOW) | _BV(RF_DR_HIGH)); // switch uses RAM (evil!) // Order matters in our case below if (dr == _BV(RF_DR_LOW)) { // '10' = 250KBPS result = RF24_250KBPS; } else if (dr == _BV(RF_DR_HIGH)) { // '01' = 2MBPS result = RF24_2MBPS; } else { // '00' = 1MBPS result = RF24_1MBPS; } return result; } uint8_t Nrf24_getCRCLength(NRF24_t * dev) { rf24_crclength_e result = RF24_CRC_DISABLED; uint8_t config; Nrf24_readRegister(dev, CONFIG, &config, sizeof(config)); //printf("CONFIG=%x\n",config); config = config & (_BV(CRCO) | _BV(EN_CRC)); uint8_t AA; Nrf24_readRegister(dev, EN_AA, &AA, sizeof(AA)); if (config & _BV(EN_CRC) || AA) { if (config & _BV(CRCO)) { result = RF24_CRC_16; } else { result = RF24_CRC_8; } } return result; } uint8_t Nrf24_getPALevel(NRF24_t * dev) { uint8_t level; Nrf24_readRegister(dev, RF_SETUP, &level, sizeof(level)); //printf("RF_SETUP=%x\n",level); level = (level & (_BV(RF_PWR_LOW) | _BV(RF_PWR_HIGH))) >> 1; return (level); } uint8_t Nrf24_getRetransmitDelay(NRF24_t * dev) { uint8_t value; Nrf24_readRegister(dev, SETUP_RETR, &value, 1); return (value >> 4); } I'm getting the following output: ... W (19498) NRF24: Maximum number of TX retries interrupt W (19498) TRANSMITTER: sending failed ... ... Update: Transmission succeeds but audio is not inteligible - 02/2023 I found out that I'm using Si24R1 (Chinese clone of nRF24L01) and I'm still using the i2s-adc esp-idf lib functions to get data from an analog microphone and I need to get this I2S stream through the SPI interface between the ESP32 and the nRF24L01 breakout board clone. Is this possible? I've seen some people mention on the internet that Nordic Semiconductors has nRF chips that support I2S but I would rather stick to the hardware I have available. Here's the link I've consulted. I've also found this library that supports audio transmission using the nRF24L01/Si24R1 chip using the nrf24.h lib but it is writeen in c++ and it is not clear to me how I could integrate it into my project. Let me know what you think the problem is or/and if you have good recommendations for learning material about this subject. Thanks for the help in advance!
Do your hardware works with a simple sender/receiver from sample codes you can find in adruino ide? If you didn't checked, have a try so you can validate the hardware is ok. If simple sender/receiver doesn't work, check your power supply lines. Sometimes not enough current from the voltage regulator. Add some caps on the rf24 module power-supply pins to filter some noise can also helps depending on the quality of the power supply. ./X
Issue in interfacing SPI e-ink display with PIC 18F46K22
I am using a PIC 18F46K22 in SPI master mode to communicate with a Waveshare 1.54" ePaper Module. The FOSC frequency is 8Mhz internal and SPI configuration is FOSC/4. So when I check the output on logic-analyzer some output bits are differ from expected. And there is some deviation in SCL. #include <xc.h> #include "config.h" #include <stdbool.h> #include <stddef.h> #include <stdint.h> #include "main.h" //#define _XTAL_FREQ 8000000 #define SPI1_DUMMY_DATA 0x0 #define SPI_RX_IN_PROGRESS 0x0 #define MY_BUFFER_SIZE 25 extern UBYTE EPD_Init(const unsigned char* lut); unsigned char myWriteBuffer[100]="Hi I'm master.."; uint8_t myReadBuffer[100]; uint8_t total; uint8_t temp; uint8_t my_data = 0x58; void UART_Init(void) { //69 SPBRG2 = 69; TXSTA2bits.BRGH = 1; BAUDCON2bits.BRG16 = 1; // Divisor at 8 bit TRISDbits.TRISD6 = 0; TRISDbits.TRISD7 = 1; RCSTA2bits.SPEN = 1; // Enable serial port TXSTA2bits.SYNC = 0; // Async operation TXSTA2bits.TX9 = 0; // No tx of 9th bit RCSTA2bits.RX9 = 0; // No rx of 9th bit TXSTA2bits.TXEN = 1; // Enable transmitter RCSTA2bits.CREN = 1; // Enable receiver } void UART_Putch(unsigned char bt) { while (!PIR3bits.TX2IF); // hold the program till TX buffer is free TXREG2 = bt; //Load the transmitter buffer with the received value } void UART_Print(unsigned const char *ptr) { while (*ptr != 0) { UART_Putch(*ptr++); } } unsigned char UART_getch() { unsigned char temp; if (RCSTA2bits.OERR) // check for Error { RCSTA2bits.CREN = 0; //If error -> Reset //__delay_ms(10); RCSTA2bits.CREN = 1; //If error -> Reset } while (!PIR3bits.RC2IF); // hold the program till RX buffer is free temp = RCREG2; return temp; //receive the value and send it to main function } void main() { ANSELA = 0; ANSELB = 0; ANSELC = 0; ANSELD = 0; TRISBbits.TRISB0 = 0; //RST Pin OUTPUT TRISBbits.TRISB1 = 0; //DC Pin OUTPUT TRISBbits.TRISB2 = 0; //CS Pin OUTPUT TRISBbits.RB3 = 1; //BUSY Pin INPUT // int i; TRISD =0;/* PORT initialize as output */ EPD_RST_PIN = 0; EPD_DC_PIN = 0; //OSCCON = 0x72; /* Use internal osc. frequency 16 MHz */ OSCCONbits.SCS = 0b10; //Frequency & PLL SETUP OSCCONbits.IRCF = 0b110; //8 MHz while (!OSCCONbits.HFIOFS); OSCTUNEbits.PLLEN = 0; //PLL disable UART_Init(); SPI_Init_Master(); /* Initialize SPI communication as a master */ if(EPD_Init(lut_full_update) != 0) { UART_Print("e-Paper init failed\r\n"); while(1); } UART_Print("e-Paper init\r\n"); for(uint8_t i = 0; i < 10; i++){ __delay_ms(10); } EPD_Clear(); UART_Print("e-Paper cleared\r\n"); for(uint8_t i = 0; i < 10; i++){ __delay_ms(50); } while(1) { // total = 0; // //do // //{ // LATAbits.LATA5=0; // //total = SPI1_Exchange8bitBuffer(SPI1_DUMMY_DATA, MY_BUFFER_SIZE, &myReadBuffer[total]); // total = SPI1_Exchange8bit(my_data); // // LATAbits.LATA5=1; // __delay_ms(500); // __delay_ms(500); // // Do something else... // // //} while(total < MY_BUFFER_SIZE); // //while(1); // // EPD_Clear(); // // __delay_ms(500); } } void SPI_Init_Master() { /* PORT definition for SPI pins*/ TRISCbits.TRISC4 = 1; /* RB0 as input(SDI) */ TRISCbits.TRISC3 = 0; /* RB1 as output(SCK) */ // TRISBbits.TRISB2 = 0; /* RA5 as a output(SS') */ TRISCbits.TRISC5 = 0; /* RC7 as output(SDO) */ /* To initialize SPI Communication configure following Register*/ EPD_CS_PIN = 1; SSP1STAT=0x00; /* Data change on rising edge of clk , BF=0*/ SSP1CON1=0x20; /* Slave mode,Serial enable, idle state high for clk */ PIR1bits.SSP1IF=0; /* Disable the ADC channel which are on for multiplexed pin when used as an input */ ADCON0=0; /* This is for de-multiplexed the SCL and SDI from analog pins*/ ADCON1=0x0F; /* This makes all pins as digital I/O */ } uint8_t SPI1_Exchange8bit(uint8_t data) { // Clear the Write Collision flag, to allow writing SSP1CON1bits.WCOL = 0; SSP1BUF = data; while(SSP1STATbits.BF == SPI_RX_IN_PROGRESS) { } return (SSP1BUF); } uint8_t SPI1_Exchange8bitBuffer(uint8_t *dataIn, uint8_t bufLen, uint8_t *dataOut) { uint8_t bytesWritten = 0; if(bufLen != 0) { if(dataIn != NULL) { while(bytesWritten < bufLen) { if(dataOut == NULL) { SPI1_Exchange8bit(dataIn[bytesWritten]); } else { dataOut[bytesWritten] = SPI1_Exchange8bit(dataIn[bytesWritten]); } bytesWritten++; } } else { if(dataOut != NULL) { while(bytesWritten < bufLen ) { temp = SPI1_Exchange8bit(SPI1_DUMMY_DATA); if(temp!=SPI1_DUMMY_DATA) { UART_Putch(temp); //uart print dataOut[bytesWritten] = temp; bytesWritten++; } __delay_ms(5); } } } } return bytesWritten; }
Compare your logic analyser SCK and MOSI timing with that specified for the part at https://www.waveshare.com/wiki/1.54inch_e-Paper_Module: Note that the MOSI (SDIN) state must be stable on the rising edge of SCK (SCLK). In your case the MOSI transitions are synchronous with the rising edge, and you have a clock transition before the MOSI has the correct D7=0 state. SPI timing is defined by both clock polarity and clock phase - giving four possible clock modes. Compare the Waveshare timing diagram with the 18F46K22 datasheet: The Waveshare diagram suggests that either CKP=1/CKE=0, or CKP=0/CKE=1 may be used, you have: SSP1STAT=0x00 ; SSP1CON1=0x20 ; Which is CKP=0/CKE=0 (which correlates with your logic analyser trace). You need on of either: SSP1STAT=0x20 ; // CKE=1 SSP1CON1=0x20 ; // CKP=0 or SSP1STAT=0x00 ; // CKE=0 SSP1CON1=0x30 ; // CKP=1 Since idle state (controlled by CKP) of SCK is a don't-care, I suggest leaving that as-is and using the first suggestion - that seems more intuitive somehow. Note also that your logic analyser must also be set to the same phase/polarity clock mode in order for its presentation of the data to be correct.
STM32 USB OTG HOST Library hangs trying to create file with FatFs
I am trying to create a file with FatFs on USB flash, but my f_open call trying to read boot sector for first time file system mount hangs on this function. DRESULT disk_read ( BYTE drv, /* Physical drive number (0) */ BYTE *buff, /* Pointer to the data buffer to store read data */ DWORD sector, /* Start sector number (LBA) */ BYTE count /* Sector count (1..255) */ ) { BYTE status = USBH_MSC_OK; if (drv || !count) return RES_PARERR; if (Stat & STA_NOINIT) return RES_NOTRDY; if(HCD_IsDeviceConnected(&USB_OTG_Core)) { do { status = USBH_MSC_Read10(&USB_OTG_Core, buff,sector,512 * count); USBH_MSC_HandleBOTXfer(&USB_OTG_Core ,&USB_Host); if(!HCD_IsDeviceConnected(&USB_OTG_Core)) { return RES_ERROR; } } while(status == USBH_MSC_BUSY ); // Loop which create hanging state } if(status == USBH_MSC_OK) return RES_OK; return RES_ERROR; } The main problem is the loop which creates hanging state while(status == USBH_MSC_BUSY ); So I do not know what to do to avoid this. Using debugger I discover that state is caused by parameter CmdStateMachine of structure USBH_MSC_BOTXferParam, type USBH_BOTXfer_TypeDef is equal CMD_UNINITIALIZED_STATE which actually cause miss up of switch statement of USBH_MSC_Read10 function. /** * #brief USBH_MSC_Read10 * Issue the read command to the device. Once the response received, * it updates the status to upper layer * #param dataBuffer : DataBuffer will contain the data to be read * #param address : Address from which the data will be read * #param nbOfbytes : NbOfbytes to be read * #retval Status */ uint8_t USBH_MSC_Read10(USB_OTG_CORE_HANDLE *pdev, uint8_t *dataBuffer, uint32_t address, uint32_t nbOfbytes) { uint8_t index; static USBH_MSC_Status_TypeDef status = USBH_MSC_BUSY; uint16_t nbOfPages; status = USBH_MSC_BUSY; if(HCD_IsDeviceConnected(pdev)) { switch(USBH_MSC_BOTXferParam.CmdStateMachine) { case CMD_SEND_STATE: /*Prepare the CBW and relevant field*/ USBH_MSC_CBWData.field.CBWTransferLength = nbOfbytes; USBH_MSC_CBWData.field.CBWFlags = USB_EP_DIR_IN; USBH_MSC_CBWData.field.CBWLength = CBW_LENGTH; USBH_MSC_BOTXferParam.pRxTxBuff = dataBuffer; for(index = CBW_CB_LENGTH; index != 0; index--) { USBH_MSC_CBWData.field.CBWCB[index] = 0x00; } USBH_MSC_CBWData.field.CBWCB[0] = OPCODE_READ10; /*logical block address*/ USBH_MSC_CBWData.field.CBWCB[2] = (((uint8_t*)&address)[3]); USBH_MSC_CBWData.field.CBWCB[3] = (((uint8_t*)&address)[2]); USBH_MSC_CBWData.field.CBWCB[4] = (((uint8_t*)&address)[1]); USBH_MSC_CBWData.field.CBWCB[5] = (((uint8_t*)&address)[0]); /*USBH_MSC_PAGE_LENGTH = 512*/ nbOfPages = nbOfbytes/ USBH_MSC_PAGE_LENGTH; /*Tranfer length */ USBH_MSC_CBWData.field.CBWCB[7] = (((uint8_t *)&nbOfPages)[1]) ; USBH_MSC_CBWData.field.CBWCB[8] = (((uint8_t *)&nbOfPages)[0]) ; USBH_MSC_BOTXferParam.BOTState = USBH_MSC_SEND_CBW; /* Start the transfer, then let the state machine manage the other transactions */ USBH_MSC_BOTXferParam.MSCState = USBH_MSC_BOT_USB_TRANSFERS; USBH_MSC_BOTXferParam.BOTXferStatus = USBH_MSC_BUSY; USBH_MSC_BOTXferParam.CmdStateMachine = CMD_WAIT_STATUS; status = USBH_MSC_BUSY; break; case CMD_WAIT_STATUS: if((USBH_MSC_BOTXferParam.BOTXferStatus == USBH_MSC_OK) && \ (HCD_IsDeviceConnected(pdev))) { /* Commands successfully sent and Response Received */ USBH_MSC_BOTXferParam.CmdStateMachine = CMD_SEND_STATE; status = USBH_MSC_OK; } else if (( USBH_MSC_BOTXferParam.BOTXferStatus == USBH_MSC_FAIL ) && \ (HCD_IsDeviceConnected(pdev))) { /* Failure Mode */ USBH_MSC_BOTXferParam.CmdStateMachine = CMD_SEND_STATE; } else if ( USBH_MSC_BOTXferParam.BOTXferStatus == USBH_MSC_PHASE_ERROR ) { /* Failure Mode */ USBH_MSC_BOTXferParam.CmdStateMachine = CMD_SEND_STATE; status = USBH_MSC_PHASE_ERROR; } else { /* Wait for the Commands to get Completed */ /* NO Change in state Machine */ } break; default: break; } } return status; } Here is USBH_BOTXfer_TypeDef type declaration; typedef struct _BOTXfer { uint8_t MSCState; uint8_t MSCStateBkp; uint8_t MSCStateCurrent; uint8_t CmdStateMachine; uint8_t BOTState; uint8_t BOTStateBkp; uint8_t* pRxTxBuff; uint16_t DataLength; uint8_t BOTXferErrorCount; uint8_t BOTXferStatus; } USBH_BOTXfer_TypeDef; During the debug I discover that all fields of it is 0x00. Here are my FatFs calls int main(void) { FATFS Fat; FIL file; FRESULT fr; RCC->AHB1ENR |= RCC_AHB1ENR_GPIODEN; /* Enable SWO output */ DBGMCU->CR = 0x00000020; GPIOD->MODER=0x55000000; GPIOD->OTYPER = 0x00000000; GPIOD->OSPEEDR = 0x00000001; while(1) { if (!USB_MSC_IsInitialized()) { USB_MSC_Initialize(); } if (USB_MSC_IsConnected()) { GPIOD->ODR = (1 << 15); disk_initialize(0); fr = f_mount(0, &Fat); if(fr == FR_OK) { fr = f_open(&file,"0:DP_lab8.pdf",(FA_CREATE_ALWAYS | FA_WRITE)); if (fr == FR_OK) { f_close(&file); } f_mount(0, NULL); } } else { GPIOD->ODR = (1 << 14); } USB_MSC_Main(); } } USB_MSC_IsConnected function is: int USB_MSC_IsConnected(void) { if (g_USB_MSC_HostStatus == USB_DEV_NOT_SUPPORTED) { USB_MSC_Uninitialize(); } return !(g_USB_MSC_HostStatus == USB_DEV_DETACHED || g_USB_MSC_HostStatus == USB_HOST_NO_INIT || g_USB_MSC_HostStatus == USB_DEV_NOT_SUPPORTED); } And device states are: typedef enum { USB_HOST_NO_INIT = 0, /* USB interface not initialized */ USB_DEV_DETACHED, /* no device connected */ USB_SPEED_ERROR, /* unsupported USB speed */ USB_DEV_NOT_SUPPORTED, /* unsupported device */ USB_DEV_WRITE_PROTECT, /* device is write protected */ USB_OVER_CURRENT, /* overcurrent detected */ USB_DEV_CONNECTED /* device connected and ready */ } USB_HostStatus; The value of g_USB_MSC_HostStatus is received by standard USB HOST user callbacks.
I think it is a bug in ST host library. I've hunted it down, as my usb host was unable to pass enumeration stage. After a fix the stack is Ok. There is union _USB_Setup in usbh_def.h file in "STM32Cube/Repository/STM32Cube_FW_F7_V1.13.0/Middlewares/ST/STM32_USB_Host_Library/Core/Inc" (any chip, not only F7, any version, not only V1.13.0). It has uint16_t bmRequestType and uint16_t bRequest. These two fileds must be uint8_t as of USB specs. Fixing this issue made usb host go as needed. Enumeration stage passes ok, and all other stages as well.
No response from UART
I'm able to receive with the following code, but unfortunately, nothing is sent back. What am I doing wrong? #include <pic18f25k80.h> #include "config.h" #include <usart.h> int i = 0; unsigned char MessageBuffer[200]; void main() { OSCCONbits.IRCF = 0b110; // 8MHz TRISB6 = 0; // TX set as output TRISB7 = 0; // RX set as output // Clear TX interrupt // Set RX interrupt // 8-bit Asynch. mode // BRGH = 1 = high baud mode // 51 = ((8MHz/baud)/16)-1 with baud = 9600 Open2USART(USART_TX_INT_OFF & USART_RX_INT_ON & USART_ASYNCH_MODE & USART_EIGHT_BIT & USART_BRGH_HIGH, 51 ); RC2IF = 0; // reset RX2 flag RC2IP = 0; // not high priority RC2IE = 1; // Eneble RX2 interrupt INTCONbits.PEIE = 1; // enable peripheral interrupts INTCONbits.GIE = 1; // enable interrupts RCSTA2bits.SPEN = 1; // enable USART while(1){ } } void interrupt ISR () { if(PIR3bits.RC2IF == 1) { if(i<200) { // buffer size MessageBuffer[i] = Read2USART(); // read byte from RX reg if (MessageBuffer[i] == 0x0D) { // check for return key puts2USART(MessageBuffer); for(;i>0;i--) MessageBuffer[i] = 0x00; // clear array i=0; return; } i++; RC2IF = 0; // clear RX flag } else { puts2USART(MessageBuffer); for(;i>0;i--) MessageBuffer[i] = 0x00; // clear array i = 0; return; } } } I'm transmitting the 0x41 hex code, I checked with the scope and see that is is being received. And according to the code I have, an echo of the received data should be sent back. When I check the TX pin, nothing is happening.
Add USART_CONT_RX to Open2USART to enable continuous receive. Also, it's a good idea to do the minimum necessary in the interrupt service routine. Consider something like: void interrupt ISR () { char data; if(PIR3bits.RC2IF == 1) { data = Read2USART(); // always read byte from RX reg (clears RC2IF) if(i<200) { // buffer size MessageBuffer[i] = data; // read byte from RX reg i++; } else{ // flag buffer full error } } } and doing the rest of what you are doing in the while(1) loop.