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.
Related
I'm trying to write a stm32 code in stm8. The problem is I can't find a SPI_Transmit function only SPI_SendData. I need this function to transmit an array through SPI.
The stm32 SPI_transmit function looks like this:
HAL_StatusTypeDef HAL_SPI_Transmit(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout)
{
uint32_t tickstart;
HAL_StatusTypeDef errorcode = HAL_OK;
uint16_t initial_TxXferCount;
/* Check Direction parameter */
assert_param(IS_SPI_DIRECTION_2LINES_OR_1LINE(hspi->Init.Direction));
/* Process Locked */
__HAL_LOCK(hspi);
/* Init tickstart for timeout management*/
tickstart = HAL_GetTick();
initial_TxXferCount = Size;
if (hspi->State != HAL_SPI_STATE_READY)
{
errorcode = HAL_BUSY;
goto error;
}
if ((pData == NULL) || (Size == 0U))
{
errorcode = HAL_ERROR;
goto error;
}
/* Set the transaction information */
hspi->State = HAL_SPI_STATE_BUSY_TX;
hspi->ErrorCode = HAL_SPI_ERROR_NONE;
hspi->pTxBuffPtr = (uint8_t *)pData;
hspi->TxXferSize = Size;
hspi->TxXferCount = Size;
/*Init field not used in handle to zero */
hspi->pRxBuffPtr = (uint8_t *)NULL;
hspi->RxXferSize = 0U;
hspi->RxXferCount = 0U;
hspi->TxISR = NULL;
hspi->RxISR = NULL;
/* Configure communication direction : 1Line */
if (hspi->Init.Direction == SPI_DIRECTION_1LINE)
{
/* Disable SPI Peripheral before set 1Line direction (BIDIOE bit) */
__HAL_SPI_DISABLE(hspi);
SPI_1LINE_TX(hspi);
}
#if (USE_SPI_CRC != 0U)
/* Reset CRC Calculation */
if (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE)
{
SPI_RESET_CRC(hspi);
}
#endif /* USE_SPI_CRC */
/* Check if the SPI is already enabled */
if ((hspi->Instance->CR1 & SPI_CR1_SPE) != SPI_CR1_SPE)
{
/* Enable SPI peripheral */
__HAL_SPI_ENABLE(hspi);
}
/* Transmit data in 16 Bit mode */
if (hspi->Init.DataSize == SPI_DATASIZE_16BIT)
{
if ((hspi->Init.Mode == SPI_MODE_SLAVE) || (initial_TxXferCount == 0x01U))
{
hspi->Instance->DR = *((uint16_t *)hspi->pTxBuffPtr);
hspi->pTxBuffPtr += sizeof(uint16_t);
hspi->TxXferCount--;
}
/* Transmit data in 16 Bit mode */
while (hspi->TxXferCount > 0U)
{
/* Wait until TXE flag is set to send data */
if (__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_TXE))
{
hspi->Instance->DR = *((uint16_t *)hspi->pTxBuffPtr);
hspi->pTxBuffPtr += sizeof(uint16_t);
hspi->TxXferCount--;
}
else
{
/* Timeout management */
if ((((HAL_GetTick() - tickstart) >= Timeout) && (Timeout != HAL_MAX_DELAY)) || (Timeout == 0U))
{
errorcode = HAL_TIMEOUT;
goto error;
}
}
}
}
/* Transmit data in 8 Bit mode */
else
{
if ((hspi->Init.Mode == SPI_MODE_SLAVE) || (initial_TxXferCount == 0x01U))
{
*((__IO uint8_t *)&hspi->Instance->DR) = (*hspi->pTxBuffPtr);
hspi->pTxBuffPtr += sizeof(uint8_t);
hspi->TxXferCount--;
}
while (hspi->TxXferCount > 0U)
{
/* Wait until TXE flag is set to send data */
if (__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_TXE))
{
*((__IO uint8_t *)&hspi->Instance->DR) = (*hspi->pTxBuffPtr);
hspi->pTxBuffPtr += sizeof(uint8_t);
hspi->TxXferCount--;
}
else
{
/* Timeout management */
if ((((HAL_GetTick() - tickstart) >= Timeout) && (Timeout != HAL_MAX_DELAY)) || (Timeout == 0U))
{
errorcode = HAL_TIMEOUT;
goto error;
}
}
}
}
#if (USE_SPI_CRC != 0U)
/* Enable CRC Transmission */
if (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE)
{
SET_BIT(hspi->Instance->CR1, SPI_CR1_CRCNEXT);
}
#endif /* USE_SPI_CRC */
/* Check the end of the transaction */
if (SPI_EndRxTxTransaction(hspi, Timeout, tickstart) != HAL_OK)
{
hspi->ErrorCode = HAL_SPI_ERROR_FLAG;
}
/* Clear overrun flag in 2 Lines communication mode because received is not read */
if (hspi->Init.Direction == SPI_DIRECTION_2LINES)
{
__HAL_SPI_CLEAR_OVRFLAG(hspi);
}
if (hspi->ErrorCode != HAL_SPI_ERROR_NONE)
{
errorcode = HAL_ERROR;
}
error:
hspi->State = HAL_SPI_STATE_READY;
/* Process Unlocked */
__HAL_UNLOCK(hspi);
return errorcode;
}
This is what the SPI_SendData function looks like:
void SPI_SendData(SPI_TypeDef* SPIx, uint8_t Data)
{
SPIx->DR = Data; /* Write in the DR register the data to be sent*/
}
Stm8 doesn't have HAL functions. I think I have to define a completely new function for this to work in stm8, but I'm not sure. Is there another way?
I think I have to define a completely new function for this to work in stm8, but I'm not sure.
Yes very likely a completely new function/driver. STM8 is an entirely different architecture compared to STM32. If you are lucky some STM8 hardware peripherals were re-used in STM32, but I doubt it since STM8 is a way older legacy architecture. For example I would guess that it only supports 8 bit mode (which is the common implementation).
The way to actually learn microcontroller programming proper, is to learn how to write drivers yourself instead of relying on various bloatware libs such as the horrible, so-called "HAL" by ST.
SPI is an excellent peripheral to use when practicing this, since it is relatively simple hardware. Some tricky things to look out for:
SPI does not transmit or receive, it transceives in full duplex.
Flag clearing in SPI peripherals is often done automatically, for example by reading a status register followed by reading a data register. This can sometimes mess up debuggers that display registers or a raw memory map, since the debugger might get the idea to read registers when you single step and thereby destroy the flags.
/SS chip select might sometimes be handled by the SPI hardware, sometimes you have to handle it manually with GPIO. Also some devices might have peculiar timing requirements forcing you to handle things manually.
You can tailor the driver for a specific application or make it more generic, at your own preference.
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
*/
--------------- EDIT: Additional Note -----------------------------------------
We just tried only migrating to Vivado 2016.1. With that version the SD card is working with the new functions, even if it destroys the audio codec somehow. Which is pretty interesting because we looked up every patch note from 2015.2 to 2016.4 and the only thing mentioned is that they added an additional data type for sd card I/O whoch is taken out again in the next version.
----------------END EDIT--------------------------------------------------------
We just migrated our robot project from vivado 2015.2 to 2016.4, after the upgrade the sd image is flashed when the fpga (zynq 7020) ist started but the processor code will not be executed. After some debugging we found out, that we have to create a new SDK project with new FSBL and BSP and include the source files with an new empty application. After this the program got stuck in a loop so we had to debug further. We then found out we had to replace our actual SD card functions ( those recommended in TRM UG585 ) with our old ones.
New SD functions:
void readBlock(unsigned char sd_id, unsigned int sector, unsigned int* buf){
unsigned int baseaddress = sd_id == 0 ? SD0_BASEADDRESS : SD1_BASEADDRESS; // Choose baseaddress based on the desired SD-slot
// START
TO_REG(baseaddress + SD_BLOCK_SIZE_REG_OFFSET) = SD_BLOCKCOUNT1_BLOCKSIZE512; // (1) Set Block Size Reg -> 512 Bytes, (2) Set Block Count Reg -> 1 Block
TO_REG(baseaddress + SD_ARGUMENT_REG_OFFSET) = sector; // (3) Set Argument Reg -> Readaddress
TO_REG(baseaddress + SD_TRANSFER_MODE_COMMAND_REG_OFFSET) = SD_SINGLEBLOCK_READ; // (4/5) Set Transfer Mode / Command Reg -> CMD17, Normal, Data Present, Enable Index-Check, Enable CRC-Check, Response length 48, Single Block, Read, Disable Auto CMD12, Disable Block Count, Disable DMA
while(!SD_CMD_COMPLETE_INTERRUPT(baseaddress)); // (6) Wait for Command Complete Interrupt
TO_REG(baseaddress + SD_INTERRUPT_STATUS_REG_OFFSET) = SD_INTERRUPT_STATUS_CMD_COMPLETE_MASK; // (7) Clear Command Complete Status
// (8) Get Response Data -> ignored, maybe checked for errors and retry
// (9) Write or Read -> Read
while(!SD_BUFFER_READ_RDY_INTERRUPT(baseaddress)); // (10-R) Wait for Buffer Read Ready Interrupt
TO_REG(baseaddress + SD_INTERRUPT_STATUS_REG_OFFSET) = SD_INTERRUPT_STATUS_BUFFER_READ_RDY_MASK; // (11-R) Clear Buffer Read Ready Status
for(unsigned char i = 0; i< 128; i++) // (12-R) Get Block Data
buf[i] = TO_REG(baseaddress + SD_BUFFER_DATA_PORT_REG_OFFSET);
// (13-R) More Blocks? -> No
// (14) Single/Multi/Infinite Block Transfer? -> Single
while(!SD_TRANSFER_COMPLETE_INTERRUPT(baseaddress)); // (15) Wait for Transfer Complete Interrupt
TO_REG(baseaddress + SD_INTERRUPT_STATUS_REG_OFFSET) = SD_INTERRUPT_STATUS_TRANSFER_COMPLETE_MASK; // (16) Clear Transfer Complete Status
// END
}
void writeBlock(unsigned char sd_id, unsigned int sector, unsigned int* buf){
unsigned int baseaddress = sd_id == 0 ? SD0_BASEADDRESS : SD1_BASEADDRESS; // Choose baseaddress based on the desired SD-slot
// START
TO_REG(baseaddress + SD_BLOCK_SIZE_REG_OFFSET) = SD_BLOCKCOUNT1_BLOCKSIZE512; // (1) Set Block Size Reg -> 512 Bytes, (2) Set Block Count Reg -> 1 Block
TO_REG(baseaddress + SD_ARGUMENT_REG_OFFSET) = sector; // (3) Set Argument Reg -> Readaddress
TO_REG(baseaddress + SD_TRANSFER_MODE_COMMAND_REG_OFFSET) = SD_SINGLEBLOCK_WRITE; // (4/5) Set Transfer Mode / Command Reg -> CMD24, Normal, Data Present, Enable Index-Check, Enable CRC-Check, Response length 48, Single Block, Write, Disable Auto CMD12, Disable Block Count, Disable DMA
while(!SD_CMD_COMPLETE_INTERRUPT(baseaddress)); // (6) Wait for Command Complete Interrupt
TO_REG(baseaddress + SD_INTERRUPT_STATUS_REG_OFFSET) = SD_INTERRUPT_STATUS_CMD_COMPLETE_MASK; // (7) Clear Command Complete
Status
// (8) Get Response Data -> ignored, maybe checked for errors and retry
// (9) Write or Read -> Write
while(!SD_BUFFER_WRITE_RDY_INTERRUPT(baseaddress)); // (10-W) Wait for Buffer Write Ready Interrupt
TO_REG(baseaddress + SD_INTERRUPT_STATUS_REG_OFFSET) = SD_INTERRUPT_STATUS_BUFFER_WRITE_RDY_MASK; // (11-W) Clear Buffer Write Ready Status
for(unsigned char i = 0; i< 128; i++) // (12-W) Set Block Data
TO_REG(baseaddress + SD_BUFFER_DATA_PORT_REG_OFFSET) = buf[i];
// (13-W) More Blocks? -> No
// (14) Single/Multi/Infinite Block Transfer? -> Single
while(!SD_TRANSFER_COMPLETE_INTERRUPT(baseaddress)); // (15) Wait for Transfer Complete Interrupt
TO_REG(baseaddress + SD_INTERRUPT_STATUS_REG_OFFSET) = SD_INTERRUPT_STATUS_TRANSFER_COMPLETE_MASK; // (16) Clear Transfer Complete Status
// END
}
Old SD functiony:
DRESULT readBlock(unsigned char sd_id, unsigned long sector, unsigned char* buff){
unsigned int count = 1;
if(sd_id > 1) return RES_ERROR; //only id = 0 or id = 1 is valid
s32 Status;
DWORD LocSector = sector;
/* Convert LBA to byte address if needed */
if ((SdInstance[sd_id].HCS) == 0U) {
LocSector *= (DWORD)XSDPS_BLK_SIZE_512_MASK;
}
Status = XSdPs_ReadPolled(&SdInstance[sd_id], (u32)LocSector, count,(unsigned char *) buff);
if (Status != XST_SUCCESS) {
return RES_ERROR;
}
return RES_OK;
}
DRESULT writeBlock(unsigned char sd_id, unsigned long sector, unsigned char* buff){
unsigned int count = 1;
if(sd_id > 1) return RES_ERROR; //only id = 0 or id = 1 is valid
s32 Status;
DWORD LocSector = sector;
/* Convert LBA to byte address if needed */
if ((SdInstance[sd_id].HCS) == 0U) {
LocSector *= (DWORD)XSDPS_BLK_SIZE_512_MASK;
}
Status = XSdPs_WritePolled(&SdInstance[sd_id], (u32)LocSector, count,buff);
if (Status != XST_SUCCESS) {
return RES_ERROR;
}
return RES_OK;
}
This fixed the problem with the processor code in general but we are still not able to initialize or do IO operations on the SD card. Additionally we found out that when initializing the SD the function getBusWidth (bsp) failes when it tries to call XSdPs_CmdTransfer() -> XSdPs_ReadReg(). Which also seems to be the case when we try to do IO ops on the SD card with our old functions.
SD init function:
unsigned char initSD(unsigned char sd_id){
if(sd_id > 1) return 0xFF; //only id = 0 or id = 1 is valid
DSTATUS s = 0;
s32 Status;
u8 SCR[8] = {0U};
u8 ReadBuff[64] = {0U};
XSdPs_Config *SdConfig = NULL;
/*
* Initialize the host controller
*/
SdConfig = &XSdPs_ConfigTable[sd_id];
Status = XSdPs_CfgInitialize(&SdInstance[sd_id], SdConfig, SdConfig->BaseAddress);
if (Status != XST_SUCCESS) {
s |= STA_NOINIT;
return s;
}
Status = XSdPs_SdCardInitialize(&SdInstance[sd_id]);
if (Status != XST_SUCCESS) {
s |= STA_NOINIT;
return s;
}
Status = XSdPs_Change_ClkFreq(&SdInstance[sd_id], SD_CLK_25_MHZ);
if (Status != XST_SUCCESS) {
s |= STA_NOINIT;
return s;
}
Status = XSdPs_Select_Card(&SdInstance[sd_id]);
if (Status != XST_SUCCESS) {
s |= STA_NOINIT;
return s;
}
Status = XSdPs_Get_BusWidth(&SdInstance[sd_id], SCR);
if (Status != XST_SUCCESS) {
s |= STA_NOINIT;
return s;
}
Status = XSdPs_Get_BusSpeed(&SdInstance[sd_id], ReadBuff);
if (Status != XST_SUCCESS) {
s |= STA_NOINIT;
return s;
}
if((ReadBuff[13] & HIGH_SPEED_SUPPORT) != 0U){
Status = XSdPs_Change_BusSpeed(&SdInstance[sd_id]);
if (Status != XST_SUCCESS) {
s |= STA_NOINIT;
return s;
}
}
Status = XSdPs_Pullup(&SdInstance[sd_id]);
if (Status != XST_SUCCESS) {
s |= STA_NOINIT;
return s;
}
if ((SCR[1] & WIDTH_4_BIT_SUPPORT) != 0U) {
Status = XSdPs_Change_BusWidth(&SdInstance[sd_id]);
if (Status != XST_SUCCESS) {
s |= STA_NOINIT;
return s;
}
}
Status = XSdPs_SetBlkSize(&SdInstance[sd_id], (u16)XSDPS_BLK_SIZE_512_MASK);
if (Status != XST_SUCCESS) {
s |= STA_NOINIT;
return s;
}
After this quite short description of our problem ;), now to my question. Has anyone of you encountered a similar problem and knows a workaround or can point us in a direction where we may find a solution?
Thanks in advance :).
Delet0r
So it worked before, which means your SD configuration seems to be right.
Have you tried the build in XSdPs_CardInitialize(...) function, instead of your customized initSD(...) function? The XSdPs_CardInitialize(...) is inside the xsdps.c of your sdps driver. This function is doing a lot more checks and also a few things in different order, as you are in your initSD(...).
So try this one:
unsigned char initSD(unsigned char sd_id){
if(sd_id > 1) return 0xFF; //only id = 0 or id = 1 is valid
DSTATUS s = 0;
s32 Status;
XSdPs_Config *SdConfig = NULL;
/*
* Initialize the host controller
*/
SdConfig = &XSdPs_ConfigTable[sd_id];
Status = XSdPs_CfgInitialize(&SdInstance[sd_id], SdConfig, SdConfig->BaseAddress);
if (Status != XST_SUCCESS) {
s |= STA_NOINIT;
return s;
}
Status = XSdPs_CardInitialize(&SdInstance[sd_id]);
if (Status != XST_SUCCESS) {
s |= STA_NOINIT;
return s;
}
return Status;
}
We also tried it with Vivado 2016.3 which works for the SD cards even if we dont know why. We have not checked yet if everything else works, but it seems like a workaround for now.
Hopefully it gets fixed in 2017.1
I'm currently doing a project, using RL78G14 as microcontroller. The project involves making an IR remote and control panel. If been trying to write code to setup a UART. I get an few warning messages of passing an incompatible pointer type when passing TxBuf and RxBuf, and my UART doesn't seem to work. Can anyone help me with the code?
void main(void)
{
R_MAIN_UserInit();
uart1Status = R_UART1_Receive(&RxBuf[0],1); // Prime UART1 Rx
while (1U)
{
//Check if byte received on UART
if (RxFlag)
{
// clear rx flag
RxFlag = 0U;
//Echo back the received character
TxBuf[0] = RxBuf[0];
//Send TX buffer, and specify how many characters to write
uart1Status = R_UART1_Send(TxBuf,1);
// re-Prime UART Rx
uart1Status = R_UART1_Receive(RxBuf,1);
}
//If a character has been transmitted
if (TxFlag)
{
// End of UART2 transmit
TxFlag = 0U; // clear tx flag
}
}
/***********************************************************************************************************************
* Function Name: R_UART1_Receive
* Description : This function receives UART1 data.
* Arguments : rx_buf -
* receive buffer pointer
* rx_num -
* buffer size
* Return Value : status -
* MD_OK or MD_ARGERROR
***********************************************************************************************************************/
MD_STATUS R_UART1_Receive(uint8_t * const rx_buf, uint16_t rx_num)
{
MD_STATUS status = MD_OK;
if (rx_num < 1U)
{
status = MD_ARGERROR;
}
else
{
g_uart1_rx_count = 0U;
g_uart1_rx_length = rx_num;
gp_uart1_rx_address = rx_buf;
}
return (status);
}
/***********************************************************************************************************************
* Function Name: R_UART1_Send
* Description : This function sends UART1 data.
* Arguments : tx_buf -
* transfer buffer pointer
* tx_num -
* buffer size
* Return Value : status -
* MD_OK or MD_ARGERROR
***********************************************************************************************************************/
MD_STATUS R_UART1_Send(uint8_t * const tx_buf, uint16_t tx_num)
{
MD_STATUS status = MD_OK;
if (tx_num < 1U)
{
status = MD_ARGERROR;
}
else
{
gp_uart1_tx_address = tx_buf;
g_uart1_tx_count = tx_num;
STMK1 = 1U; /* disable INTST1 interrupt */
TXD1 = *gp_uart1_tx_address;
gp_uart1_tx_address++;
g_uart1_tx_count--;
STMK1 = 0U; /* enable INTST1 interrupt */
}
return (status);
}
If you are using development board, R11 Pin check. It is connected to CAN RXD chip TJA1050T, and hence not receiving any data. Cut R11 jumper and it will start working.
Did you Started UART1 ? need to start it in Initialization.
I have been playing around with ATtiny's and arduino for a while but am a complete newbee in 'real' AVR programming.
I am building a laser gun and target for my son and want to have the target play a random silly animal sound whenever it is hit.
The other functions of the target is maintained by Attiny85s and i therefore stumbled upon Elm-Chans code for interfacing a microSD card with Attiny85 and play .wav files by PWM.
However the code is written so that it plays files on the SD card root folder (or other dir) in order and skips to next in response to a pushbutton on one of the pins.
What i want it to do is to pick and play a random file from the root when button is pushed (i.e. target is hit).
It should play the sound only once and preferably interrupt an already playing file and play another if the target is hit again before the sound has ended.
I have been trying really hard to figure out what to change in the code but come to realize that i need to start from the beginning with learning AVR programming from scratch...however that will take some time and before i get there i humbly hope that any of you could grant me a quick fix and tell me what to do, so i can finish the toy.
Kind regards
Mads
/*----------------------------------------------------------------------------/
/ 8-pin SD audio player R0.05d (C)ChaN, 2011 /
/-----------------------------------------------------------------------------/
/ This project, program codes and circuit diagrams, is opened under license
/ policy of following trems.
/
/ Copyright (C) 2010, ChaN, all right reserved.
/
/ * This project is a free software and there is NO WARRANTY.
/ * No restriction on use. You can use, modify and redistribute it for
/ personal, non-profit or commercial use UNDER YOUR RESPONSIBILITY.
/ * Redistributions of source code must retain the above copyright notice.
/
/----------------------------------------------------------------------------*/
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
#include <avr/wdt.h>
#include <string.h>
#include "pff.h"
#include "xitoa.h"
#ifndef MODE
#error Wrong make file.
#endif
#if MODE == 0 /* Single output */
FUSES = {0xE1, 0xDD, 0xFF}; /* Fuse bytes for mono: Low, High and Extended */
#else /* Dual output */
FUSES = {0xE1, 0x7D, 0xFF}; /* Fuse bytes for stereo and mono-HR: Low, High and Extended (*HVS mode only*) */
#endif
/* This is the fuse settings of this project. The fuse data will be included
in the output hex file with program code. However some old flash programmers
cannot load the fuse bits from hex file. If it is the case, remove this line
and use these values to program the fuse bits. */
#define FCC(c1,c2,c3,c4) (((DWORD)c4<<24)+((DWORD)c3<<16)+((WORD)c2<<8)+(BYTE)c1) /* FourCC */
void delay_us (WORD); /* Defined in asmfunc.S */
/*---------------------------------------------------------*/
/* Work Area */
/*---------------------------------------------------------*/
volatile BYTE FifoRi, FifoWi, FifoCt; /* FIFO controls */
BYTE Buff[256]; /* Wave output FIFO */
FATFS Fs; /* File system object */
DIR Dir; /* Directory object */
FILINFO Fno; /* File information */
WORD rb; /* Return value. Put this here to avoid avr-gcc's bug */
/*---------------------------------------------------------*/
static
DWORD load_header (void) /* 0:Invalid format, 1:I/O error, >=1024:Number of samples */
{
DWORD sz, f;
BYTE b, al = 0;
if (pf_read(Buff, 12, &rb)) return 1; /* Load file header (12 bytes) */
if (rb != 12 || LD_DWORD(Buff+8) != FCC('W','A','V','E')) return 0;
for (;;) {
wdt_reset();
pf_read(Buff, 8, &rb); /* Get Chunk ID and size */
if (rb != 8) return 0;
sz = LD_DWORD(&Buff[4]); /* Chunk size */
switch (LD_DWORD(&Buff[0])) { /* Switch by chunk ID */
case FCC('f','m','t',' ') : /* 'fmt ' chunk */
if (sz & 1) sz++; /* Align chunk size */
if (sz > 100 || sz < 16) return 0; /* Check chunk size */
pf_read(Buff, sz, &rb); /* Get content */
if (rb != sz) return 0;
if (Buff[0] != 1) return 0; /* Check coding type (LPCM) */
b = Buff[2];
if (b != 1 && b != 2) return 0; /* Check channels (1/2) */
GPIOR0 = al = b; /* Save channel flag */
b = Buff[14];
if (b != 8 && b != 16) return 0; /* Check resolution (8/16 bit) */
GPIOR0 |= b; /* Save resolution flag */
if (b & 16) al <<= 1;
f = LD_DWORD(&Buff[4]); /* Check sampling freqency (8k-48k) */
if (f < 8000 || f > 48000) return 4;
OCR0A = (BYTE)(F_CPU / 8 / f) - 1; /* Set sampling interval */
break;
case FCC('d','a','t','a') : /* 'data' chunk */
if (!al) return 0; /* Check if format is valid */
if (sz < 1024 || (sz & (al - 1))) return 0; /* Check size */
if (Fs.fptr & (al - 1)) return 0; /* Check word alignment */
return sz; /* Start to play */
case FCC('D','I','S','P') : /* 'DISP' chunk */
case FCC('L','I','S','T') : /* 'LIST' chunk */
case FCC('f','a','c','t') : /* 'fact' chunk */
if (sz & 1) sz++; /* Align chunk size */
pf_lseek(Fs.fptr + sz); /* Skip this chunk */
break;
default : /* Unknown chunk */
return 0;
}
}
return 0;
}
static
void ramp (
int dir /* 0:Ramp-down, 1:Ramp-up */
)
{
#if MODE != 3
BYTE v, d, n;
if (dir) {
v = 0; d = 1;
} else {
v = 128; d = (BYTE)-1;
}
n = 128;
do {
v += d;
OCR1A = v; OCR1B = v;
delay_us(100);
} while (--n);
#else
dir = dir ? 128 : 0;
OCR1A = (BYTE)dir; OCR1B = (BYTE)dir;
#endif
}
static
FRESULT play (
const char *dir, /* Directory */
const char *fn /* File */
)
{
DWORD sz;
FRESULT res;
BYTE sw;
WORD btr;
wdt_reset();
xsprintf((char*)Buff, PSTR("%s/%s"), dir, fn);
res = pf_open((char*)Buff); /* Open sound file */
if (res == FR_OK) {
sz = load_header(); /* Check file format and ready to play */
if (sz < 1024) return 255; /* Cannot play this file */
FifoCt = 0; FifoRi = 0; FifoWi = 0; /* Reset audio FIFO */
if (!TCCR1) { /* Enable audio out if not enabled */
PLLCSR = 0b00000110; /* Select PLL clock for TC1.ck */
GTCCR = 0b01100000; /* Enable OC1B as PWM */
TCCR1 = MODE ? 0b01100001 : 0b00000001; /* Start TC1 and enable OC1A as PWM if needed */
TCCR0A = 0b00000010; /* Statr TC0 as interval timer at 2MHz */
TCCR0B = 0b00000010;
TIMSK = _BV(OCIE0A);
ramp(1);
}
pf_read(0, 512 - (Fs.fptr % 512), &rb); /* Snip sector unaligned part */
sz -= rb;
sw = 1; /* Button status flag */
do { /* Data transfer loop */
wdt_reset();
btr = (sz > 1024) ? 1024 : (WORD)sz;/* A chunk of audio data */
res = pf_read(0, btr, &rb); /* Forward the data into audio FIFO */
if (rb != 1024) break; /* Break on error or end of data */
sz -= rb; /* Decrease data counter */
sw <<= 1; /* Break on button down */
} while ((PINB & 1) || ++sw != 1);
}
while (FifoCt) ; /* Wait for audio FIFO empty */
OCR1A = 128; OCR1B = 128; /* Return output to center level */
return res;
}
static
void delay500 (void)
{
wdt_reset();
TCCR0B = 0; TCCR0A = 0; /* Stop TC0 */
if (TCCR1) { /* Stop TC1 if enabled */
ramp(0);
TCCR1 = 0; GTCCR = 0;
}
WDTCR = _BV(WDE) | _BV(WDIE) | 0b101; /* Set WDT to interrupt mode in timeout of 0.5s */
set_sleep_mode(SLEEP_MODE_PWR_DOWN); /* Enter power down mode */
sleep_mode();
wdt_reset();
WDTCR = _BV(WDE) | 0b110; /* Set WDT to reset mode in timeout of 1s */
}
EMPTY_INTERRUPT(WDT_vect);
/*-----------------------------------------------------------------------*/
/* Main */
int main (void)
{
FRESULT res;
char *dir;
BYTE org_osc = OSCCAL;
MCUSR = 0;
WDTCR = _BV(WDE) | 0b110; /* Enable WDT reset in timeout of 1s */
PORTB = 0b101001; /* Initialize port: - - H L H L L P */
DDRB = 0b111110;
sei();
for (;;) {
if (pf_mount(&Fs) == FR_OK) { /* Initialize FS */
wdt_reset();
Buff[0] = 0;
if (!pf_open("osccal")) pf_read(Buff, 1, &rb); /* Adjust frequency */
OSCCAL = org_osc + Buff[0];
res = pf_opendir(&Dir, dir = "wav"); /* Open sound file directory */
if (res == FR_NO_PATH)
res = pf_opendir(&Dir, dir = ""); /* Open root directory */
while (res == FR_OK) { /* Repeat in the dir */
res = pf_readdir(&Dir, 0); /* Rewind dir */
while (res == FR_OK) { /* Play all wav files in the dir */
wdt_reset();
res = pf_readdir(&Dir, &Fno); /* Get a dir entry */
if (res || !Fno.fname[0]) break; /* Break on error or end of dir */
if (!(Fno.fattrib & (AM_DIR|AM_HID)) && strstr(Fno.fname, ".WAV"))
res = play(dir, Fno.fname); /* Play file */
}
}
}
delay500(); /* Delay 500ms in low power sleep mode */
}
}
I reckon your case requires more C-coding knowledge than AVR-hacking one.
Here:
if (!(Fno.fattrib & (AM_DIR|AM_HID)) && strstr(Fno.fname, ".WAV"))
res = play(dir, Fno.fname); /* Play file */
Every time matching file is found, play function is called. What you want instead is to add this file descriptor to some form of container (e.g. list) of available files. After all files are listed, you may want to wait for external input (hit by laser), and then play the file and move current file index to the next.
To enable pausing and resetting playback, I recommend using external interrupt for handling "on hit" events.
PS Building toys for your kid using AVR? +1 from me!