Packing an array and only process when full - c

I'm working on an embedded c app. The app downloads a file and writes to flash memory. The requirements are that I can only write to flash in blocks of 64 bytes (1 page). THe binary firmware file gets downloaded in chunks no bigger than 64 bytes (e.g. 64 or less bytes). However I am getting the data is different lengths. For example:
1st packet size :62 bytes
2nd packet size :64
3rd packet size :64
4th packet size :64
5th packet size :43
6th packet size :64
....
last packet: length: 7
I need to keep track of the bytes, pack the bytes into a buffer until its full (64 bytes) then write to flash.
I am having a heck a time figuring this out. Here is what I have so far, but is not right and my rmdBuff gets thrown off. I am looking for some guidance.
Global vars
uint8_t temp[64]; // buffer to send when full
uint8_t rmdBuff[64]; // buffer to pack
uint8_t temp_indx;
uint8_t rmd_indx;
uint8_t buffer_room_needed; // keep track of how much room in rmdBuff
uint8_t rem_offset;
uint16_t bit_ct; // how many bits processed
uint16_t rowct; // for debugging
Function
void store_file_packet(char *data, uint32_t length)
{
if ((data == NULL) || (length < 1)) {
return;
}
if (!is_state_set(DOWNLOADING)) {
printf("********* Initial Start of Download **************\n\r");
received_file_size = 0;
add_state(DOWNLOADING);
temp_indx = 0;
rmd_indx = 0;
buffer_room_needed = 0;
rem_offset = 0;
bit_ct = 0;
rowct = 1;
}
if (data != NULL) {
memset(temp, 0, sizeof temp); // clear temp
if(rmd_indx > 0){
// figure out how much room we have in rmd array
buffer_room_needed = 64 - rmd_indx;
rem_offset = abs(length - buffer_room_needed);
memcpy(&rmdBuff[rmd_indx],&data[0],buffer_room_needed); // only copy over what we have room for
rmd_indx = rmd_indx + buffer_room_needed;
if(rmd_indx > 63){ // rmd buffer is full
memcpy(temp,&rmdBuff,64); // copy over all 64 bytes
memset(rmdBuff, 0, sizeof rmdBuff); // clear rmdBuff
temp_indx = 63;// full
rmd_indx = 0;
// add anything else to rmdBuff?
memcpy(&rmdBuff[rmd_indx],&data[buffer_room_needed + 1],rem_offset);
rmd_indx += rem_offset;
}
} else {
if(length != 64){
// not enough, copy over to hold array
memcpy(rmdBuff,&data[0],length);
rmd_indx += length;
} else {
memcpy(temp,&data[0],length); // copy over all 64 bytes
temp_indx = 63; // full
}
}
if(temp_indx == 63){
// write temp buffer to memory
}
}
}

Related

Arduino: Read from SD card to char array, then save to SD card

I am working with Arduino and Lora. Arduino A has a camera, Lora radio and SD card. Arduino B has the same setup minus the camera. Plan is to take a picture on Arduino A and save it to the SD card, then read and via Lora send to Arduino B which will save the information on its own SD card.
My current milestone is to read a test text file in the SD card and save it as a copy on the same card, all within Arduino A.
This worked reading and writing byte by byte using the standard SD library, however it's too slow.
I want to read 100 bytes (eventually 512) and save it to a buffer (char array), write those 100 bytes to the SD card in one write instruction, and repeat until the file is completly written.
I am not succeding in spliting the text into blocks, especially when there are less than 100 bytes in the file. Beguiner at C. Code follows. Thank you!
oFile = SD.open("message.txt", FILE_READ); // Original file
cFile = SD.open("message2.txt", FILE_WRITE); // Copy
int cIndex = 0;
char cArray[101]; // Buffer for the blocks of data
int cByteTotal = oFile.available(); // Get total bytes from file in SD card.
for(int i=0; i < cByteTotal ; i++){ // Looping
cArray[cIndex] = (char)myFile.read(); //Cast byte as char and save to char array
if (cIndex == 100 ){ // Save 100 bytes in buffer
cArray[cIndex + 1] = '\0'; // Terminate the array?
Serial.println(String(cArray)); // Print to console
cFile.write(cArray); // Save 100 bytes to SD card.
memset(cArray, 0, sizeof(cArray)); // Clear the array so that its ready for next block
cIndex = -1; // Reset cIndex for next loop
}
if (cByteAvailable <= 99){ // When cByteTotal is less than 100...
Serial.print("Last block");
}
cIndex++;
}
oFile.close();
cFile.close();
From the SD.read() documentation I would suggest using the read(buf, len) format to read a maximum of 100 bytes per go. And similarly for SD.write() . Something like this should go faster:
int cByteTotal = oFile.size();
while (cByteTotal > 0) {
int length = cByteTotal < 100 ? cByteTotal : 100;
if (length < 100) {
Serial.print("Last block");
}
oFile.read(cArray, length);
cFile.write(cArray, length);
cByteTotal -= length;
}
oFile.close();
cFile.close();

Weird correlation between I2C Transfer and Array size

So... i don't even know how to explain this...
I have a cc1310 Launchpad XL and a tiny EEPROM. My task is to write a library for easy transferring. In Code Composer Studio I'm using an Example project from TI with TIRTOS to test my functions. The weird thing is:
when i am declaring a uint8_t array larger than 304. my Transactions wont work. Itll only send 1 Byte and freezes.
Under 305, everything is fine.
Oh and im not even using the array. It just has to exist and nothing works.
void *mainThread(void *arg0)
{
uint32_t *pAddress;
int i;
uint8_t dat = 0;
uint32_t address = 0x00FEAA;
uint8_t data[305] = {0};
uint32_t datalen = sizeof(data);
for(i=0; i< 305; i++)
{
data[i]=dat;
dat++;
}
pAddress=&address;
int write = EEPROM_sWrite(pAddress, data,datalen);
return 0;
}
and
int EEPROM_sWrite(uint32_t *address, uint8_t *data, uint32_t datalen)
{
I2C_init();
//needed variables and initialization
uint8_t writebuf[258] = {0};
uint8_t blocksize = 0;
uint8_t *p = &writebuf[2];
if((*address+datalen)>maxAddress) //out of bounds?
{
return 1;
}
else
{
I2C_Transaction Transaction = {0};
Transaction.slaveAddress = slaveAddressA;
Transaction.writeBuf = writebuf;
Transaction.writeCount = blocksize;
Transaction.readBuf = NULL;
Transaction.readCount =0;
I2C_Params params;
I2C_Params_init(&params);
params.bitRate = I2C_400kHz;
params.transferMode = I2C_MODE_BLOCKING;
I2C_Handle Handle = I2C_open(0,&params );
//first block
if(*address>0xFFFF) //second half of the memory?
{
Transaction.slaveAddress = slaveAddressB;
}
blocksize = maxPagesize - (*address & 0xFF)+1;
//blocksize needs to be adjusted to the page size
writebuf[0] = (*address & 0xFF00) >> 8; //page address
writebuf[1] = (*address & 0xFF); //cell Address
if(datalen<=blocksize) //if it fits in a single page, just do it
{
memcpy(p,data,datalen);
//copies data to buffer (fills only needed cells in page)
Transaction.writeCount = datalen+2;
if(I2C_transfer(Handle, &Transaction))
{
I2C_close(Handle);
return 0;
}
else
{
I2C_close(Handle);
return 1;
}
}
memcpy(p,data,blocksize);//copies data to buffer (fills complete page)
Transaction.writeCount = blocksize+2;
if(!I2C_transfer(Handle, &Transaction))
{
I2C_close(Handle);
return 1;
}
usleep(10000);
//loop preparation
data+=blocksize;//shifts pointer forward
datalen-=blocksize; //reduces blocksize
writebuf[0]++; //next page
writebuf[1] = 0; //start cell is now 0 each time
//nth block
while(datalen>maxPagesize) //cut down to page sized blocks and write it down
{
//copy 256 bytes of data to buffer
memcpy(p,data,maxPagesize);
//send it
Transaction.writeCount = maxPagesize+2;
if(!I2C_transfer(Handle, &Transaction))
{
I2C_close(Handle);
return 1;
}
usleep(10000);
//preparation
data+=maxPagesize;
datalen-=maxPagesize;
//checks if it exceeds the first memory half
if(writebuf[0]==0xff)
{
Transaction.slaveAddress=slaveAddressB;
writebuf[0]=0;
}
else
{
writebuf[0]++; //next page
}
}
//last block
//copy last data
memcpy(p,data,datalen);
//send it
Transaction.writeCount = datalen+2;
if(!I2C_transfer(Handle, &Transaction))
{
I2C_close(Handle);
return 1;
}
I2C_close(Handle);
return 0;
}
}
edit:
#define maxAddress 0x1FFFF
#define maxPagesize 0xFF
forgot them..
A Reddit user had the right idea!
Turns out it was a simple stack overflow.
The Stack size of the thread was 1024. As i changed it to 2048, everything works.

File system, unexpected write/read on disk output

I've been working on this for 3 days, can't see the error, I need fresh eyes :)
I work on a online embedded class, and at this particular lab we need to implement a file system.
I have unexpected results as described in the code comments in the main function. (E=expected, R=result)
Write/read functions:
#define EDISK_ADDR_MIN 0x00020000 // Flash Bank1 minimum address
#define EDISK_ADDR_MAX 0x0003FFFF // Flash Bank1 maximum address
// Write an array of 32-bit data to flash starting at given address.
int Flash_FastWrite(uint32_t *source, uint32_t addr, uint16_t count)
{
uint32_t flashkey;
uint32_t volatile *FLASH_FWBn_R = (uint32_t volatile*)0x400FD100;
int writes = 0;
if(MassWriteAddrValid(addr))
{
DisableInterrupts(); // may be optional step
while(FLASH_FMC2_R&FLASH_FMC2_WRBUF){}; // wait for hardware idle
while((writes < 32) && (writes < count))
{
FLASH_FWBn_R[writes] = source[writes];
writes = writes + 1;
}
FLASH_FMA_R = addr;
if(FLASH_BOOTCFG_R&FLASH_BOOTCFG_KEY) // by default, the key is 0xA442
flashkey = FLASH_FMC_WRKEY;
else // otherwise, the key is 0x71D5
flashkey = FLASH_FMC_WRKEY2;
FLASH_FMC2_R = (flashkey|FLASH_FMC2_WRBUF); // start writing
while(FLASH_FMC2_R&FLASH_FMC2_WRBUF){};
EnableInterrupts();
}
return writes;
}
// Write 1 sector of 512 bytes of data to the disk, data comes from RAM
enum DRESULT eDisk_WriteSector(
const uint8_t *buff, // Pointer to the data to be written
uint8_t sector){ // sector number
uint32_t addr;
uint32_t *copybuff;
copybuff =(uint32_t*)(buff);//Flash_WriteArray needs uint32_t format
addr=EDISK_ADDR_MIN+(512*sector);// starting ROM address
if(addr>EDISK_ADDR_MAX) // return RES_PARERR if exceeds
return RES_PARERR;
Flash_WriteArray(copybuff, addr, 512);// write 512 bytes from RAM into ROM
// written by the instructor.
return RES_OK;
}
// Read 1 sector of 512 bytes from the disk, data goes to RAM
enum DRESULT eDisk_ReadSector(
uint8_t *buff, // Pointer to a RAM buffer into which to store
uint8_t sector){ // sector number to read from
uint16_t i;
uint8_t *diskpt;
diskpt=(uint8_t *)(EDISK_ADDR_MIN+512*sector); // starting ROM address
if(EDISK_ADDR_MIN+512*sector>EDISK_ADDR_MAX)
return RES_PARERR;
else
{
for ( i = 0; i < 512; i++ )// copy 512 bytes from ROM into RAM
buff[i] = *diskpt++;
return RES_OK;
}
}
enum DRESULT eDisk_Format(void){
// erase all flash from EDISK_ADDR_MIN to EDISK_ADDR_MAX
for(uint32_t i=EDISK_ADDR_MIN;i<=EDISK_ADDR_MAX;i++)
Flash_Erase(i);
return RES_OK;
}
uint8_t Buff[512];
int main(void)
{
eDisk_Init(0); // if(drive == 0){return RES_OK;}
eDisk_Format();
testbuildbuff("auf0");
eDisk_WriteSector(Buff,0);
testbuildbuff("Excelent"); // writes "Excelent" onto Buff
eDisk_WriteSector(Buff,1);
testbuildbuff("bus3");
eDisk_WriteSector(Buff,2);
testbuildbuff("bus4");
eDisk_WriteSector(Buff,3);
// E=expected. R=result
eDisk_ReadSector(Buff, 0); //E: Buff="auf0" R:Buff="auf0"
eDisk_ReadSector(Buff, 1); //E: Buff="Excelent" R: Buff is empty
eDisk_ReadSector(Buff, 2); //E: Buff="bus3" R: Buff is empty
eDisk_ReadSector(Buff, 3); //E: Buff="bus4" R: 4Buff is empty
return 0;
}
The Buff results after reed are unexpected. Why does it work for 0 but not the rest?
Even more strange is when I run this test:
testbuildbuff("auf0 buf1 buf2");
eDisk_WriteSector(Buff,2);
testbuildbuff("Excelent");
eDisk_WriteSector(Buff,1);
testbuildbuff("bus3");
eDisk_WriteSector(Buff,3);
testbuildbuff("bus4");
eDisk_WriteSector(Buff,4);
eDisk_ReadSector(Buff, 4); //Buff is empty
eDisk_ReadSector(Buff, 3); //Buff is empty
eDisk_ReadSector(Buff, 2); //Buff = "auf0 buf1 buf2"
eDisk_ReadSector(Buff, 1); //Buff = "Excelent"
What is happening?
PS: IDE Keil uVision v5.2, uC: TM4C123
The issue is at call of function Flash_WriteArray().
In Flash_WriteArray(), the last parameter should be the number of words (32-bit or 4 bytes) we want to write. To write 512 bytes, this parameter should be 128 (512/4).
Writing words and reading bytes may give you an endian issue if your cpu is big endian.

STM32F4Discovery - SDCard sector reading

long time I try to implement FatFs module, but its gets crazy after every sd card formatting. (different errors each time). I've decided to go lower and check my SDCard drivers and I've noticed that when I read some (but ALWAYS THE SAME) of sector's field I receive garbage and I can't interpret it.
My driver's test looks like below:
#if 1 //SD Card Test
uint16_t i;
uint8_t CSD; //card capacity
uint8_t CID; //card id
uint8_t Buffer[512]; //this buffer is written to card
for(i=0; i<512;i++)
{
Buffer[i]=i;
}
SD_CardInit(); //card initialization
CSD = SD_Read_CSD(); //read capacity
CID = SD_Read_CSD(); //read ID
SD_WriteBlock(0x200, Buffer, 512); //write Buffer under 0x200 (512) address
SD_Read_Block(0x200); //read buffer from 0x200
CSD = 0;
#endif
I put breakpoint at CSD = 0; line. Here is what I get after writing and reading the same address:
Buffer is filled with numbers from 0 to 255 (two times, because of overflow).
To reduce noise I've minimized SPI frequency to minimum. Nothing changed. But in fact that wrong numbers appears ALWAYS under the same table index and with the same values suggest that is no problem with noise, but some error.
It looks like drivers works properly, because they write and read most of the fields, but always in the same it answer with garbage. I can't find any trace what could I do wrong. Do I write under some permitted address? When I read any random address I receive the same result.
I include functions: read and write (SD_Sector is a global buffer)
WRITE
// Write block of data to the SD card
// input:
// addr - start address of the block (must be power of two)
// pBuf - pointer to the buffer with data
// len - buffer length
// return: SDR_xxx
SDResult_TypeDef SD_WriteBlock(uint32_t addr, uint8_t *pBuf, uint32_t len)
{
uint32_t wait;
uint16_t CRC_loc; // Calculated CRC16 of the block
uint16_t i;
uint8_t cmdres, response, temp;
SDCard_privChipSelect();
// Calculate 16-bit CRC
CRC_loc = CRC16_buf(pBuf,len);
// SDSC card uses byte unit address and
// SDHC/SDXC cards use block unit address (1 unit = 512 bytes)
// For SDHC/SDXC card addr must be converted to block address
#if 0 //TODO: reconsider PiechotM, do not work with that line
if (SD_CardType == SD_HIGH_CAPACITY_SD_CARD) addr >>= 9;
#endif
response = SD_SendCmd(SD_CMD_WRITE_SINGLE_BLOCK,addr); // CMD24
if (response != 0x00)
{
// Something wrong happened, do nothing
return response; // SD_CMD_READ_SINGLE_BLOCK command returns bad response
}
else
{
wait = 0; response = 0;
while (++wait <= 512/*0x1ff*/ && response == 0xff)
{
temp = 0xFF;
SD_Send( temp );
response = SD_Recv();
}
if (wait >= 0x1ff) return 0xff;
// Send start block token
SD_Send(SD_TOKEN_START_BLOCK);
// Send data block
for (i = 0; i < len; i++)
{
uint8_t temp;
SD_Send( *pBuf++ );
}
// Send CRC
SD_Send(CRC_loc >> 8);
SD_Send((uint8_t)CRC_loc);
}
// Get response from the SD card
cmdres = SD_Recv();
cmdres &= 0x1f;
if (cmdres != SD_TOKEN_DATA_ACCEPTED)
{
// Data block rejected by SD card for some reason
// Release SD card
SD_Send(0xff);
SDCard_privChipDeSelect();
if (cmdres & SD_TOKEN_WRITE_CRC_ERROR) return SDR_WriteCRCError;
if (cmdres & SD_TOKEN_WRITE_ERROR) return SDR_WriteErrorInternal;
return SDR_WriteError;
}
// Wait while the SD card is busy by data programming
wait = 0x7fff; // Recommended timeout is 250ms (500ms for SDXC)
do
{
cmdres = SD_Recv();
} while (cmdres == 0 && --wait);
// Provide extra 8 clocks for the card (from SanDisk specification)
SD_Send(0xff);
// Release SD card
SDCard_privChipDeSelect();
// Must send at least 74 clock ticks to SD Card
for (wait = 0; wait < 10; wait++) SD_Send(0xff);
return SDR_Success;
}
READ
// return:
// 0x00 -- read OK
// 0x01..0xfe -- error response from CMD17
// 0xff -- timeout
uint8_t SD_Read_Block(uint32_t addr)
{
uint32_t wait;
uint16_t i;
uint8_t response;
SDCard_privChipSelect();
#if 0 //TODO: reconsider PiechotM, do not work with that line
if (SD_CardType != SD_HIGH_CAPACITY_SD_CARD) addr <<= 9; // Convert block number to byte offset
#endif
response = SD_SendCmd(SD_CMD_READ_SINGLE_BLOCK,addr); // CMD17
if (response != 0x00)
{
// Something wrong happened, fill buffer with zeroes
for (i = 0; i < 512; i++) SD_sector[i] = 0;
return response; // SD_CMD_READ_SINGLE_BLOCK command returns bad response
}
else
{
wait = 0; response = 0;
while (++wait <= 0x1ff && response != 0xfe) response = SD_Recv();
if (wait >= 0x1ff) return 0xff;
// Read 512 bytes of sector
for (i = 0; i < 512; i++) SD_sector[i] = SD_Recv();
}
// Receive 16-bit CRC (some cards demand this)
SD_CRC16_rcv = SD_Recv() << 8;
SD_CRC16_rcv |= SD_Recv();
// Calculate CRC16 of received buffer
SD_CRC16_cmp = CRC16_buf(&SD_sector[0],512);
SDCard_privChipDeSelect();
// Must send at least 74 clock ticks to SD Card
for (wait = 0; wait < 8; wait++) SD_Send(0xff);
return 0;
}
/* -------------------- WRITE SECTION ------------------------------*/
/* Lonely Wolf library imported */
/*------------------------PiechotM----------------------------------*/
// Send buffer to the SD card
// input:
// pBuf - pointer to the buffer
// len - length of the buffer
// return: last response from SD card
void SD_WriteBuf(uint8_t *pBuf, uint16_t len)
{
while (len--) SD_Send(*pBuf++);
}
I will be very thankful for your help!
Best regards,
Maks Piechota

How to correctly receive data through SPI enhanced buffer mode of Microchip PIC24F microcontrollers?

I'm programming a SPI communication with an external RF chip. The microcontroller is the model PIC24FJ64GA102 from Microchip.
I want to use the enhanced buffer mode of the SPI.
Problem: Get the received bytes out of the receive buffer.
Used SPI function:
void SPI1_get(uint8_t* data, uint16_t length) {
uint16_t i = 0, l = length;
uint8_t dummy;
while (length > 0) {
while (SPI1STATbits.SPITBF || SPI1STATbits.SPIRBF) {
dummy = SPI1STAT;
}
do {
SPI1BUF = 0xff;
} while (SPI1STATbits.SPIRBF == 0 && --length > 0);
do {
while (SPI1STATbits.SRMPT == 0) {
}
data[i] = SPI1BUF;
++i;
} while (i < l && SPI1STATbits.SRXMPT != 1);
}
}
Here the calls:
uint8_t cmd[2]; cmd[0] = length; cmd[1] = address;
SPI1_put(cmd,2); // e.g: 0x02, 0x01
SPI1_get(buf,2); // e.g: 0x05, 0x01 (received data)
The communication is just fine, checked with an oscilloscope and SPI decoding module. The data on the SPI bus are like in the comment above: sent 0x02 0x01 0xff 0xff, received 0x00 0x00 0x05 0x01, but the function above does not correctly retrieve the data out of the receive buffer. I've already tested a lot of constellations of checking flags and interrupts but in the end the best result I can get is: 0x00 0x01 (only the last byte is correct).
Also already checked the errata sheet, where two SPI problems are mentioned which do not (should not) affect my code.
What the hell am I doing wrong?!
As requested here the SPI1_put() function:
void SPI1_put(uint8_t* data, uint16_t length) {
uint16_t i = 0;
uint8_t dummy;
for (; i < length; ++i) {
while (SPI1STATbits.SPITBF)
; // maybe change to (_SPI1BEC == 7) ?
SPI1BUF = data[i];
dummy = SPI1BUF; //dummy read
}
}
[latest edit: 2015-02-05]
So today I was able to spend some more time on this particular issue, and came up with a port of ElderBug's suggestion, also taking care of the bugs mentioned in the errata sheet:
uint8_t out_buf[128];
uint8_t in_buf[128];
void SPI1_com(uint8_t* out, uint8_t* in, uint16_t out_len, uint16_t in_len) {
uint16_t len = out_len + in_len;
uint16_t sent = 0, recv = 0, i = 0;
// while (!SPI1STATbits.SRXMPT)
sent = SPI1BUF; // empty buffer
sent = SPI1BUF; // empty buffer
sent = 0;
if (out != out_buf && out != 0)
memcpy(out_buf, out, out_len);
while (sent < len && recv < len) {
if (SPI1STATbits.SPIBEC != 7 && sent < len) {
SPI1BUF = out_buf[sent++];
}
if (!SPI1STATbits.SRXMPT && recv < len) {
in_buf[recv] = SPI1BUF, recv++;
}
}
if (in != 0) {
for (i = 0; i < in_len; ++i) {
in[i] = in_buf[out_len + i];
}
// memcpy(in, in_buf + out_len, in_len);
}
for (i = 0; i < len; ++i) {
out_buf[i] = 0xff;
in_buf[i] = 0xff;
}
}
This code basically works. With an exception which I was not able to work around:
The communication works as follows:
1byte: r/w-bit+length
1byte: address
1-127byte: data
So, when I read 1 byte from the slave chip, meaning sending 3 bytes (rw+len, address, dummybyte), the data I have in my in_buf buffer is 0xFF.
Now a weird thing: When I just read one more byte, without changing anything (just one more dummy byte on the bus), the 1st byte of my in_buf has got the correct data. But this seems not to work always, because my program still stucks at some points.
I'm left sitting here with a lot of question marks.
Weird thing the 2nd: Reading 8 bytes, data correct in my buffer until the last byte, last byte is 0xFF, should be 0x00. Wtf?
PS: Already filed a ticket at Microchip for support in this issue.
There is a problem in your SPI1_put.
In your SPI1_put function, you read SPI1BUF right after starting the transfer, and thus you read when the transfer is not complete (correct me if I'm wrong, but reading when the FIFO is empty doesn't block and just return the previous byte). The function should be something like :
void SPI1_put(uint8_t* data, uint16_t length) {
uint16_t sent = 0;
uint16_t rec = 0;
uint8_t dummy;
while(1)
{
if( !SPI1STATbits.SPITBF && sent < length )
SPI1BUF = data[sent++];
if( !SPI1STATbits.SRXMPT && rec < length )
dummy = SPI1BUF, rec++;
if( sent == length && rec == length )
break;
}
}
About the SPI1_get, I think it's fine, but I'm not sure. The thing is, it should look very similar to SPI1_put, because SPI is really symmetric in how it works :
void SPI1_get(uint8_t* data, uint16_t length) {
uint16_t sent = 0;
uint16_t rec = 0;
while(1)
{
if( !SPI1STATbits.SPITBF && sent < length )
SPI1BUF = 0xff, sent++;
if( !SPI1STATbits.SRXMPT && rec < length )
data[rec++] = SPI1BUF;
if( sent == length && rec == length )
break;
}
}
Overall, since you only do synchronous calls, the enhanced buffer is not really useful. You could have simpler functions with the same results just by doing 'send, wait, receive' for each byte.
EDIT after your update :
Your new code looks correct, except for the condition in the while that you did wrong. Here is the corrected code with some modifications with comments that may improve it (removed the buffer copies) :
// No additional buffers
void SPI1_com(uint8_t* out, uint8_t* in, uint16_t out_len, uint16_t in_len) {
uint16_t len = out_len + in_len;
uint16_t sent = 0, recv = 0, i;
uint16_t dummy;
// After the call, SPI comms should have ended and RX FIFO should be empty.
// If SPI1STATbits.SRXMPT is not 1 here,
// it means there is a problem in the code. Report it somehow for debug ?
// if( !SPI1STATbits.SRXMPT )
// error!
// This loop is harmless but shouldnt be needed
//while (!SPI1STATbits.SRXMPT)
//dummy = SPI1BUF; // empty buffer
i = 0;
while (sent < len || recv < len) {
if (SPI1STATbits.SPIBEC != 7 && sent < len) {
// Here we are out of the buffer when sent>=out_len,
// but it's ok because random bytes are fine here
SPI1BUF = out[sent++];
}
if (!SPI1STATbits.SRXMPT && recv < len) {
if( recv < out_len )
// Before out_len, discard the data
dummy = SPI1BUF;
else
// After out_len, store the data in in[]
in[i++] = SPI1BUF;
recv++;
}
}
}
Does this correct any bug ? Also, this may sound stupid, but are you calling that correctly ? I don't know what you did, but for your 1 byte read, it should be SPI1_com(two_byte_buffer,one_byte_buffer,2,1);.
One more point : it seems that you always try to empty the RX FIFO at the beginning. Is there actually something in the FIFO ? SPI1STATbits.SRXMPT MUST be 1 without even trying to empty. If it isn't, there IS a bug somewhere in software. Do you have any other code using the SPI ?

Resources