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.
Related
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
}
}
}
As mentioned I have a Zynq SoC (ZC706 Eval Board) and I'm trying to read an image from the SD Card. To do this I'm using the FatFs lib (http://elm-chan.org/fsw/ff/00index_e.html).
In my code I read 4096 Byte from the file and save it to a buffer. After that i copy the buffer to an unsigned char pointer that size I increase after every read operation.
Then I'm using realloc, the for loop in the copyU32ArrayToUnsignedCharArray function 'failed' because the size variable is overwritten by the out array.
Code that overwrite the "size" in the copyU32ArrayToUnsignedCharArray function:
u32 buffer[1024];
unsigned char *img = NULL;
bytesreaded = 0;
for (;;) {
br=0;
fr = f_read(&fil, buffer, sizeof(buffer), &br); /* Read a chunk of source file */
if (fr || br == 0)
break; /* error or eof */
img = realloc(img,br);
copyU32ArrayToUnsignedCharArray(buffer, &img[bytesreaded], br/4); // /4 because u32(32 bit) in to unsigned char(8 bit)
bytesreaded += br; // update readed bytes
}
The code that worked:
u32 buffer[1024];
unsigned char *img = NULL;
img = malloc(512*512*3+100);
bytesreaded = 0;
for (;;) {
br=0;
fr = f_read(&fil, buffer, sizeof(buffer), &br); /* Read a chunk of source file */
if (fr || br == 0)
break; /* error or eof */
copyU32ArrayToUnsignedCharArray(buffer, &img[bytesreaded], br/4); // /4 because u32(32 bit) in to unsigned char(8 bit)
bytesreaded += br; // update readed bytes
}
The copyU32ArrayToUnsignedCharArray function:
void copyU32ArrayToUnsignedCharArray(u32 *in, unsigned char* out, uint size){
int i,x;
x = 0;
for (i = 0; i < size; i++) {
if(size != 1024)
break;
in[i] = Xil_In32BE(&in[i]);
out[x] = (u32) in[i] >> 24;
out[x + 1] = (u32) in[i] >> 16 & 0x00FF;
out[x + 2] = (u32) in[i] >> 8 & 0x0000FF;
out[x + 3] = (u32) in[i] & 0x000000FF;
x += 4;
}
}
I want to use realloc because I don't know how big the image will be that I read.
Update:
Some further information to the code that doesn't work. I debugged it and the pointer to *img isn't null, so the realloc was successfully. If I'm using gdb the following things happen in the copyU32ArrayToUnsignedCharArray function:
- pointer to the variable "out" is 0x001125a8
- the address of the "size" variable is 0x0011309c (the value that is stored at this location is correct)
- the space in memory between this two variables is 0xaf4 = 2804 dec (difference of the two addresses)
- if the for loop within the copyU32ArrayToUnsignedCharArray function reached i=702 and x=2808 the size variable is changed to another value
Sincerely,
Arno
I solved the problem with the hint from Notlikethat. The problem was the small heap size. Increasing the heap is done by editing the linker script file
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
I have a hex file of 327680 characters which I'm writing to physical address 0x30000000 - 0x3004FFFF on the memory on my ARM linux system.
While reading back from the memory I'm getting a segfault after reading 64170 characters from the start address, ie at 0x3000FAAA.
If I change my starting address to 0x3000FA64, then also I get a segfault after 64170 characters.
How do I ensure data is accessed correctly if Data > 4kB (page size) ?
I'm unable to understand the exact problem, so I'm adding the snippet of my code below:
#define MAX_RANGE 327679
int fd;
FILE* fd_table=NULL;
unsigned long int count = 0 ;
void * mem;
void * aligned_vaddr;
unsigned long aligned_paddr;
uint32_t aligned_size;
unsigned long int addr_phys;
uint8_t *addr;
int g_size = 1;
unsigned long int g_paddr = 0x30000000; //Starting physical address
while((count<MAX_RANGE)){
g_paddr = addr_phys;
g_paddr &= ~(g_size - 1);
aligned_paddr = g_paddr & ~(4096 - 1);
aligned_size = g_paddr - aligned_paddr + (g_count * g_size);
aligned_size = (aligned_size + 4096 - 1) & ~(4096 - 1);
/* Align address to access size */
aligned_vaddr = mmap(NULL, aligned_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, aligned_paddr);
if (aligned_vaddr == NULL) {
printf("Error mapping address\n");
close(fd);
return 1;
}
mem = (void *)((uint32_t)aligned_vaddr + (g_paddr - aligned_paddr));
addr = mem;
fprintf(fd_table, "%02X\n",addr[0]);
addr_phys +=1; //Increment byte address
count++;
}
Note:
1. There is no error in the write process, I have verified by viewing the segfault address with memtool.
2. The address 0x30000000 onwards is not used by the system (I have ensured that in the u-boot).
I'm working in the arduino environment. I have a struct defined as follows. The struct will ultimately be encrypted and sent wirelessly over a radio link layer. It's 32bytes long.
struct SENSORTYPE{
int sensor1:8;
int sensor2:8;
int sensor3:8;
int sensor4:8;
};
struct SENSOR{
float sensor1;
float sensor2;
float sensor3;
float sensor4;
};
struct HEADER{
byte type;
short id;
short to;
short from;
byte version;
long _buff;
SENSORTYPE sensortype;
SENSOR sensor;
};
HEADER header;
I have an XTEA encryption/decryption routine that's defined as follows and is verified to work. It operates on two 32bit blocks at at time.
void xteaEncrypt( unsigned long v[2])
void xteaDecrypt(unsigned long v[2])
What I'm trying to do is run header through xteaEncrypt. I'm getting tripped up on converting my struct to the two 32bit numbers. The following is what I have so far.
#define BLOCK_SIZE 8
header.type = 1; //test value
header._buff = 1; //test value
byte data[BLOCK_SIZE]; //8 byte buffer to encrypt/decrypt
byte buff[32]; //32 byte buffer to put encrypted/decrypted data into
for (uint32_t i = 0; i < 4; i++){ //4 times (4 * 8 = 32)
memcpy(data, &header+(i*BLOCK_SIZE), BLOCK_SIZE); //copy 8 bytes from header struct into data
xteaEncrypt((uint32_t*)data); //encrypt data
memcpy(&buff+(i*8), data, BLOCK_SIZE); //put encrypted data into the new buffer
}
memcpy(&header, &buff, sizeof(header)); //copy into original header for convenience
//now decrypt it back
for (uint32_t i = 0; i < 4; i++){
memcpy(data, &header+(i*BLOCK_SIZE), BLOCK_SIZE);
xteaDecrypt((uint32_t*)data);
memcpy(&buff+(i*8), data, BLOCK_SIZE);
}
memcpy(&header, &buff, sizeof(header));
After encryption header.type = 0xee and header._buff = C0010000. After decryption, header.type = 1 and _buff still = C0010000 so it would seem there is an error in my memcpy'ing but I can't find it. Any help would be greatly appreciated. This one has been particularly hard to debug for me. If I'm going about this completely wrong let me know and point me in the right direction.
You're getting tripped up by pointer arithmetic. Consider the snippet &header+(i*BLOCK_SIZE). What you evidently expect to happen is that you'll get some address, let's call it addr, and then add some small number to it to calculate a new address, i.e.
finalAddress = addr + (i * 8);
But because &header is a pointer to a struct HEADER, the actual calculation the compiler does is
finalAddress = addr + (sizeof(struct HEADER) * i * 8);
The result is an address that's well beyond the end of the header for any i greater than 0. The same thing is happening with &buff+(i*8), since &buff is a pointer to 32 bytes.
To solve the problem, I recommend using intermediate variables that are char *, e.g.
char *headAddress = (char *)&header;
char *buffAddress = (char *)&buff;
for (uint32_t i = 0; i < 4; i++)
{
memcpy(data, headAddress+(i*BLOCK_SIZE), BLOCK_SIZE);
xteaEncrypt((uint32_t*)data);
memcpy(&buffAddress+(i*BLOCK_SIZE), data, BLOCK_SIZE);
}