I am trying to design a pipelined cpu simulator. The code is fairly complex, atleast for me. There are multiple header and source files. The code compiles.
On running, it runs fine in the first iteration(clock cycle). But not so from the iteration. After spending hours on finding the fault, I found out what is wrong but don't know why. Following function:
MemoryAccess(ir, pc, ground, '0', instrMem);
fetches an instruction at index "pc" in instrMem and store it in "ir". Following are the declarations of the variables in the function:
typedef char bit32[33];
bit8 instrMem[4096]; /* instruction memory */
bit32 pc, ir, ground;
The problem is that from the second iteration onwards, value of "ir" remains "00000000". I have checked instrMem, the values are not all 0s. I also checked the working of MemoryAccess() using driver function. It works fine.
I can't undertand why it works fine for the first iteration and not from then on.
Can someone please help. Is there a way of finding out what's wrong?
following is the relevant part of main() function:
for(cycle=0; ; cycle++)
{
/* load IR with PC value */
printf("I am at the beginning of the cycle loop");
MemoryAccess(ir, pc, ground, '0', instrMem);
/* report fetched register values */
printf("cycle: %d, PC: %.32s (%d), IR: %.32s\n\t", cycle, pc, bit32toint(pc), ir);
/* halt check */
if (bit32toint(ir) == 0x0000003F) {
printf("\nmachine halted\n");
break;
}
/* PC + 4 data path */
RCAdder_32(pcPlus4, ground, pc, "00000000000000000000000000000100", '0');
/* jump data path */
shiftleftby2(jumpAddress, ir);
jumpAddress[0] = pcPlus4[0];
jumpAddress[1] = pcPlus4[1];
jumpAddress[2] = pcPlus4[2];
jumpAddress[3] = pcPlus4[3];
/* sign extended / shifted immediate data path */
signextend(immSignExt, &ir[16]);
shiftleftby2(immShifted, immSignExt);
/* control unit data path */
ControlUnit(ir, &ir[26], ®Write, ®Dest,
&memRead, &memWrite, &memToReg,
&jump, &branch, &aluSrc, aluOp);
/* register memory data path - read */
Mux2_5(regWriteAddr, &ir[11], &ir[16], regDest);
registerAccess(®Out1, ®Out2, &ir[6], &ir[11], regWriteAddr, regIn, '0');
/* alu data path */
Mux2_32(aluSrcVal, regOut2, immSignExt, aluSrc);
zero = ALU(&aluOut, regOut1, aluSrcVal, aluOp);
/* branch data path */
RCAdder_32(branchAddress, ground, pcPlus4, immShifted, '0');
Mux2_32(mbranchAddress, pcPlus4, branchAddress, AND2_1(zero, branch));
Mux2_32(pc, mbranchAddress, jumpAddress, jump);
/* main memory data path */
MemoryAccess(memOut, aluOut, regOut2, memWrite, mainMem);
Mux2_32(regIn, aluOut, memOut, memToReg);
/* register memory data path - write */
registerAccess(®Out1, ®Out2, &ir[6], &ir[11], regWriteAddr, regIn, regWrite);
/* dump register memory and signal information */
for (i=0; i < 14; i++) {
inttobitn(i, 5, tmp);
registerAccess(®Out1, ®Out2, tmp, &ir[11], regWriteAddr, regIn, '0');
printf("R%d: %d, ", i, bit32toint(regOut1));
}
printf("\b\b\n\tbranchAddress = %.32s (%d) jumpAddress = %.32s (%d)\n",
branchAddress, bit32toint(branchAddress), jumpAddress, bit32toint(jumpAddress));
printf("\topcode = %.6s, immSignExt = %.32s (%d), immShifted = %.32s (%d), PC+4 = %.32s (%d)\n",
ir, immSignExt, bit32toint(immSignExt), immShifted, bit32toint(immShifted), pcPlus4, bit32toint(pcPlus4));
printf("\tregWrite = %c, regDest = %c, memRead = %c, memWrite = %c, memToReg = %c, jump = %c, branch = %c, aluSrc = %c, aluOp = %.3s, zero = %c\n",
regWrite, regDest, memRead, memWrite, memToReg, jump, branch, aluSrc, aluOp, zero);
getchar();
}
Following is the MemoryAccess() function:
void MemoryAccess(bit32 read_out, bit32 addr, bit32 write_in, signal write_enable, bit8 memory[4096]){
int address= bitntoint(12, addr);
setbit8(read_out, memory[address]);
setbit8(&read_out[8], memory[address+1]);
setbit8(&read_out[16], memory[address+2]);
setbit8(&read_out[24], memory[address+3]);
if (write_enable){
setbit8(memory[address], write_in);
setbit8(memory[address+1], &write_in[8]);
setbit8(memory[address+2], &write_in[16]);
setbit8(memory[address+3], &write_in[24]);
}
}
Setbit8(a, b) copies b into a and appends '\0'.
To long for a comment:
1 The code shown does not seem to be increasing pc.
2 Although you pass '0' as writabel flag, it is not used as intended. You might like to change
if (write_enable)
to be
if (write_enable && ('0' != (*write_enable)))
Due to the former version memory is overwritten with what is referenced by the pointer passed into as 3rd parameter (write_in), which propably are 0s.
Related
I write the program in C, and I'm using windows.
I have a program that take an exe from the user, and every 5 instructions I put a break point so it's become harder to crack the program. I'm using disassembly library to make sure that the opcode that I replaced is the first opcode of an instruction. Every time that I replace opcode with 0XCC I write the address of the opcode and the original opcode on a table. After the replace, I open a new process with debug flag and every time there is a break point, the child process throw an exception, and the father process replace the 0XCC with the original opcode. The code that replace the opcode to the original look something like this:
address = (DWORD)debug_event->u.Exception.ExceptionRecord.ExceptionAddress;
if (!VirtualProtectEx(pi->hProcess, (LPVOID)address, sizeof(BYTE), PAGE_READWRITE, &last_protect)) {
log_error("VirtualProtectEx failed LAST ERROR: %d", GetLastError());
goto l_cleanup;
}
log_trace("Trying to write the opcode: [0x%x] to the address: [0x%x]", *opcode, address);
if (!WriteProcessMemory(pi->hProcess, (LPVOID)address, opcode, sizeof(BYTE), &number_of_bytes_write)) {
log_error("WriteProcessMemory failed LAST ERROR: %d", GetLastError());
goto l_cleanup;
}
if (!VirtualProtectEx(pi->hProcess, (LPVOID)address, sizeof(BYTE), last_protect, &last_protect)) {
log_error("VirtualProtectEx failed LAST ERROR: %d", GetLastError());
goto l_cleanup;
}
log_trace("Successfully changed the opcode to the original one");
ctx.ContextFlags = CONTEXT_FULL;
if (!GetThreadContext(pi->hThread, &ctx)) {
log_error("GetThreadContext failed LAST ERROR: %d", GetLastError());
goto l_cleanup;
}
log_trace("Trying to change the EIP with the value: [0x%lx] to the value: [0x%x]", ctx.Eip, address);
ctx.Eip -= 1;
if (!SetThreadContext(pi->hThread, &ctx)) {
log_error("SetThreadContext failed LAST ERROR: %d", GetLastError());
goto l_cleanup;
}
I also have a while loop that run until the exception of the exit process.
This is the code that change the instruction and update the table:
address_of_code = text_section.VirtualAddress - text_section.PointerToRawData;
for (INT counter = 0; counter < count - 1; ++counter)
{
if (0 == counter % 5) {
loaded_PE->data[instructions[counter].address] = 0xCC;
info.address = instructions[counter].address + address_of_code;
info.opcode = instructions[counter].bytes[0];
info.length = instructions[counter].size;
log_trace("address: %x", instructions[counter].address +
address_of_code);
log_trace("instruction: %s", instructions[counter].mnemonic);
log_trace("length: %d", instructions[counter].size);
if (!INFO_TABLE__update_table(&info, table)) {
log_error("INFO_TABLE__update_table failed");
goto l_cleanup;
}
}
}
Instructions is an array that I recieve from the library Capstone. The loaded_PE-> store the data of the PE from the client. I call the disassembly function with the address of the entry point and the size of the code - the entry point. Counter is the number of the instructions the capstone library found. Info struct hold the information about the replace.
This is the call for the disassembly library:
count = cs_disasm(handle, data, size_to_modify, entry_point - text_section.VirtualAddress
+ text_section.PointerToRawData, 0, &instructions);
Now to my problem. I'm taking a simple program like this:
int main() {
char str[] = "hello";
printf("%s\n", str);
return 0;
I start to replace the instructions from the entry point. Now if I run the program that debug the new program I get the print and everything works fine. But if I change the number of instructions that I replace to every 10 instructions, I get an error. After the "hello" I get an access violation. After I checked the address of this access violation, I found that the program try to read 4 bytes before the address of the string on the stack and failed.
this is the line that try to read the location
this is the string and the address that the program trying to read
I don't understand why sometimes it's work and sometimes it's not.
One more thing. If I change the program to be like this:
int main() {
char* str = "hello";
printf("%s\n", str);
return 0;
I don't get any errors.
I hope I explained myself fine. Thanks for the help!
I hope this is a clear explanation of my issue I've been runnign around various manuals for a little over a week now tryign to solve this:
Recently I have been redesigning a software design for a class project after feedback and testing on the STM32 Nucleo-F334R8(my initial code was riddled with memory and timing errors)
Currently I run into two main errors:
(This issue has been resolved)
I had been using sprintf not accounting for the trailing null character writting outside of allocated memory.
When processing USART Data using USART 1 in Asynchronous mode at
115200 Baudrate:
Program received signal SIGTRAP, Trace/breakpoint trap. 0x08002c08 in
memset ()
Program received signal SIGTRAP, Trace/breakpoint trap. 0x08002c08 in
memset ()
Program received signal SIGTRAP, Trace/breakpoint trap. 0x08002c08 in
memset ()
Program received signal SIGTRAP, Trace/breakpoint trap. 0x08002c08 in
memset ()
Program received signal SIGTRAP, Trace/breakpoint trap. 0x080056b4 in
std.isra ()
The value stored at the address 0x08002c08 in question is usually very
large typically something like 134228385 in decimal. Also if I
forcefully step through the issue the program continues to run fine
and never encounters the problem again which I find strange
possible cause?
UPDATE: So
I've traced the memset issue around a bit and found that it occurs
during my setOutputBuffer method:
String>,%5d,%8s,%3d,%3d,%3d,%4d,%4d,%4d,%10.6f,%11.6f,%7.1f,%3d,%3.1f\n",uptime,timeString,temperature,pressure,humidity,acc1,acc2,acc3,latitude,longitude,altitude,current,voltage);
} ``` Which leads me to believe the issue lies in finding a value that
is being used to set the Output buffer message.
I would like advice on how to further troubleshoot these two issues
and whether there is a chance that the memset error is related the
later bss error.
My String Tokenizing code(edited):
```c void tokenize(char* in){ const char *p = in; const char
delim[] = ","; char *token = NULL; uint8_t n = 0;
do{
size_t length = strcspn(p, delim); if(length > 0){ if(token ==
NULL){
token = malloc(sizeof(char)*length); // create memory space for the token
memset(token, 0, length); // ensure initialized memory is blank
sprintf(token, "%.*s",(int)length,p); // store the token from a substring of Input Buffer
p+=length; // move pointer to next ','
parseToken(token, n); // extract information from the token be it latitude, longitude etc
memset(token, 0, length); // clear the token
free(token); // free up the token's spot in memory
token = NULL; // set token pointer to null
n++; }
}
}while(*((++p)+1) != '*'); // The expected string ends with a
checksum character '*' after the last ',' } ``` I've re-examined the
function and made a lot of changes now I can successfully step through
the entire function without issue, the program then returns to my main
loop, and I let it run for a while but then I suddenly run back into
the same memset issue, even without receiving any bytes over USART
here is the code for my main loop and the subsequent function calls it
makes:
```c
while (1) {
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
if (byteFlag){ byteRecieved(); byteFlag = 0; }
if(msgFlag){ msgRecieved(); msgFlag = 0; }
if(secFlag){ setOutputBuffer(); HAL_UART_Transmit(&huart1,
(uint8_t *)bufferOut, 91, 1000); secFlag = 0; }
} ``` byteReceived: ```c if((char) byteIn == '$'){
clearInputBuffer(); } else if((char) byteIn == '\n'){
msgFlag = 1; }
else{ storeChar(); } ```
msgReceived: ```c if(isValid()){ if (checksum()) {
tokenize(bufferIn); clearInputBuffer(); } } ```
isValid: ```c char substr[5]; strncpy(substr, (bufferIn+1), 5);
if(!strcmp(substr, "GPGGA")){ return 1; }
return 0; ```
checksum: ```c int checksum(){ int calc_checksum = 0; int
in_checksum; int i = 0; char checkstr[2]; uint8_t hasCheckSum = 0;
for(int j = 0; j<91; j++){ if (bufferIn[j] == '*') { hasCheckSum
= 1; i = 1; } }
if (hasCheckSum) { while (bufferIn[i] != '*'){ calc_checksum ^=
bufferIn[i]; i++; } checkstr[0] = bufferIn[i+1]; checkstr[1]
= bufferIn[i+2]; } else {return 0;}
in_checksum = parseStr_HexToInt(checkstr);
if (calc_checksum == in_checksum){ return 1; } else { return 0;
} } ```
clearInputBuffer: ```c void clearInputBuffer(){ int i = 0;
for(i = 0; i < 100; i++){ bufferIn[i] = ' '; } bufferIn[0] = '$';
} ```
(This issue has been resolved)
Essentially the source of my problem was misuse of sprintf and overwritting program code with null characters
I encountered a breakpoint trap while filling the bss segment of the
board's memory
And after adding Seven GPIO Ports for a 4bit mode LCD(namely PA12,
PA11, PB12, PB11, PB2, PB1, PB15) and two for a two channel ADC in DMA
mode (PA1, PA0):
Program received signal SIGTRAP, Trace/breakpoint trap.
LoopFillZerobss () at ..\startup/startup_stm32f334x8.s:103 103 cmp r2,
r3 While trying to implement LCD and ADC functionality I receive the breakpoint trap error during the LoopFillZerobss function of
startup which proved fatal, particularly by stopping my USART
from reporting at all(however it can still receive bytes as
interrupt and process tokens etc, just refuses to transmit), After
reading up into the bss segment I attempted to solve the issue by
initializing as many global variables as I could to non-zero values,
this did not work, the problem is observed after adding the
STM32CubeMx settings for ADC and the 7 GPIO pins used in the LCD,
however none of these use unitialized variables to my knowledge
unless the predefined code generated by CubeMX is going beyond the
bounds of the bss segment of memory and that the size of the bss
segment is too large now for the board's memory (which I suspect is
unlikely but can't rule out).
Essentially the idea of this project is to receive various data over USART, ADC and later I2C and display various aspects of the data over USART and LCD at currently if I discard the ADC and LCD errors my USART code functions as the memset() error is non-lethal but I suspect that leaving it there is only causing me later issues but I'm also not sure where to fix my tokenizing code, assuming it is the root of my issues.
Essentially the source of my problem was misuse of sprintf and overwritting program code with null characters
By ensuring to use snprintf rather than sprintf with well defined sized strings I ran into no more memory issues.
This is going to be a bit abstract due to the specific ARM (LPCXpresso 1115R/303) Cortex M0 and the H6 bluetooth module, and with NXP software there are a ton of driver files that are linked so hopefully the code snip below will be enough to identify the problem.
I am creating a simple menu system through bluetooth. Everything works with communcation. I send the message from the board, it is visible on the phone, I respond and print the value in the console of the program. All are exactly what I want them to be. But this is what happens:
1) start debug session and resume
2) 1st menu sends to phone, correct.
3) Type response to phone and send, correct.
4) message appears in console exactly as entered from phone (Just the number 1 appears)
5) Have if loop that checks to see if Buffer value == '1';
6) must not == 1 because it never enters the loop.
7) reprints the value of the buffer, and it still equals 1.
The only hint I have is a warning that says "makes integer from pointer without a cast [-Wint-conversion]" on the assignment line as indicated below.
void ArmPeripheral() {
UARTCount = 0;
LPC_UART->IER = IER_THRE | IER_RLS; /* Disable RBR */
UARTSend( (uint8_t *)menu1, sizeof(menu1));
LPC_UART->IER = IER_THRE | IER_RLS | IER_RBR; /* Re-enable RBR */
while(1) {
if(UARTCount != 0){
printf("%s 1st print\n",UARTBuffer);
int bVal = UARTBuffer; // This is where the error occurs, tried uint8_t, did not work.
printf("%s This is bVal\n",bVal);
if(bVal == 1) { //have tried 1, '1', and "1" none work
printf("inside loop %s...\n",UARTBuffer);
printf("%s This is bVal\n",bVal);
LEDControl();
}
printf("%s second print\n",UARTBuffer);
UARTCount = 0;
}
}
}
enter image description here
Nevermind, it was just a simple pointer issue. UARTBuffer is a external volatile uint8_t in the UART.c file, and even though it is not defined as a pointer, it is pointing to a buffer somehow.
int bVal = *UARTBuffer;
if(bVal == '1') {
The above worked, but if anyone has any more in depth information that could explain why I would be interested in knowing. This is how I initialized the buffer:
extern volatile uint32_t UARTCount;
extern volatile uint8_t UARTBuffer[BUFSIZE];
I have been trying for the last few weeks to find out why this isn't working. I have tried reading all the documentation I could find on my PIC32 MCU (PIC32MX795F512L) and the XC32 compiler I am using (v1.34) but with no success as of yet.
I need a special constant value written to the physical boot flash address 0x1FC02FEC (Virtual address: 0x9FC02FEC). This constant is 0x3BDFED92.
I have managed to successfully do this on my main program (If I program my pic32 directly using Real ICE) by means of the following command line (Which I put in xc32-ld under "Additional options" under the Project Properties):
--fill=0x3bdfed92#0x9FC02FEC
I am then able to check (Inside my main program) if this address indeed does have the correct value stored inside it, and this works too. I use the following code for that:
if(*(int *)(0x9fc02fec) == 0x3bdfed92)
My problem is the following. I do not want my main program hex file to write the constant into that location. I want my bootloader hex file to do this and my main program must just be able to read that location and see if that constant is there. If I use the --fill command inside the xc32-ld of my bootloader program, it successfully writes the constant just like the main program did (I have tested this by running my bootloader program with the same --fill command in debug mode and checking the 0x1FC02FEC address for the constant). Problem is, when my bootloader reads in a new main program via the MicroSD, and then jumps to the new main program, everything doesn't work. Seems like, before it jumps to the new main program, something bad happens and everything crashes. Almost like writing a value to the 1FC02FEC location is a problem when the program jumps from boot loader to main program.
Is there a reason for this? I hope my explanation is ok, if not then please let me know and I will try reword it in a more understandable way.
I am using the example code provided by Microchip to do the bootloader using the MicroSD card. The following is the code:
int main(void)
{
volatile UINT i;
volatile BYTE led = 0;
// Setup configuration
(void)SYSTEMConfig(SYS_FREQ, SYS_CFG_WAIT_STATES | SYS_CFG_PCACHE);
InitLED();
TRISBbits.TRISB14 = 0;
LATBbits.LATB14 = 0;
ClrWdt();
// Create a startup delay to resolve trigger switch bouncing issues
unsigned char x;
WORD ms = 500;
DWORD dwCount = 25;
while(ms--)
{
ClrWdt();
x=4;
while(x--)
{
volatile DWORD _dcnt;
_dcnt = dwCount*((DWORD)(0.00001/(1.0/GetInstructionClock())/10));
while(_dcnt--)
{
#if defined(__C32__)
Nop();
Nop();
Nop();
#endif
}
}
}
if(!CheckTrigger() && ValidAppPresent())
{
// This means the switch is not pressed. Jump
// directly to the application
JumpToApp();
}
else if(CheckTrigger() && ValidAppPresent()){
if(MDD_MediaDetect()){
if(FSInit()){
myFile = FSfopen("image.hex","r");
if(myFile == NULL){
JumpToApp();
}
}
else{
JumpToApp();
}
}
else{
JumpToApp();
}
}
//Initialize the media
while (!MDD_MediaDetect())
{
// Waiting for media to be inserted.
BlinkLED();
}
// Initialize the File System
if(!FSInit())
{
//Indicate error and stay in while loop.
Error();
while(1);
}
myFile = FSfopen("image.hex","r");
if(myFile == NULL)// Make sure the file is present.
{
//Indicate error and stay in while loop.
Error();
while(1);
}
// Erase Flash (Block Erase the program Flash)
EraseFlash();
// Initialize the state-machine to read the records.
record.status = REC_NOT_FOUND;
while(1)
{
ClrWdt();
// For a faster read, read 512 bytes at a time and buffer it.
readBytes = FSfread((void *)&asciiBuffer[pointer],1,512,myFile);
if(readBytes == 0)
{
// Nothing to read. Come out of this loop
// break;
FSfclose(myFile);
// Something fishy. The hex file has ended abruptly, looks like there was no "end of hex record".
//Indicate error and stay in while loop.
Error();
while(1);
}
for(i = 0; i < (readBytes + pointer); i ++)
{
// This state machine seperates-out the valid hex records from the read 512 bytes.
switch(record.status)
{
case REC_FLASHED:
case REC_NOT_FOUND:
if(asciiBuffer[i] == ':')
{
// We have a record found in the 512 bytes of data in the buffer.
record.start = &asciiBuffer[i];
record.len = 0;
record.status = REC_FOUND_BUT_NOT_FLASHED;
}
break;
case REC_FOUND_BUT_NOT_FLASHED:
if((asciiBuffer[i] == 0x0A) || (asciiBuffer[i] == 0xFF))
{
// We have got a complete record. (0x0A is new line feed and 0xFF is End of file)
// Start the hex conversion from element
// 1. This will discard the ':' which is
// the start of the hex record.
ConvertAsciiToHex(&record.start[1],hexRec);
WriteHexRecord2Flash(hexRec);
record.status = REC_FLASHED;
}
break;
}
// Move to next byte in the buffer.
record.len ++;
}
if(record.status == REC_FOUND_BUT_NOT_FLASHED)
{
// We still have a half read record in the buffer. The next half part of the record is read
// when we read 512 bytes of data from the next file read.
memcpy(asciiBuffer, record.start, record.len);
pointer = record.len;
record.status = REC_NOT_FOUND;
}
else
{
pointer = 0;
}
// Blink LED at Faster rate to indicate programming is in progress.
led += 3;
mLED = ((led & 0x80) == 0);
}//while(1)
return 0;
}
If I remember well (very long time ago I used PIC32) you can add into your linker script:
MEMORY
{
//... other stuff
signature (RX) : ORIGIN = 0x9FC02FEC, length 0x4
}
then
SECTIONS
{
.signature_section:
{
BYTE(0x3b);
BYTE(0xdf);
BYTE(0xed);
BYTE(0x92);
}>signature
}
Googling around I also found out, that you could do that in your source code, I hope...
const int __attribute__((space(prog), address(0x9FC02FEC))) signature = 0x3bdfed92;
In my program I use an attribute to place a certain value at a certain location in memory space. My bootloader and App can read this location. This may be a simpler way for you to do this. This is using xc16 and a smaller part but I've done it on a PIC32 as well.
#define CHECK_SUM 0x45FB
#define CH_HIGH ((CHECK_SUM & 0xFF00) >> 8)
#define CH_LOW ((CHECK_SUM & 0x00FF) >> 0)
const char __attribute__((space(prog), address(APP_CS_LOC))) CHKSUM[2] = {CH_LOW,CH_HIGH};
Just a note, when you read it, it will be in the right format: HIGH->LOW
I'm developing on an AD Blackfin BF537 DSP running uClinux. I have a total of 32MB SD-RAM available. I have an ADC attached, which I can access using a simple, blocking call to read().
The most interesting part of my code is below. Running the program seems to work just fine, I get a nice data package that I can fetch from the SD-card and plot. However, if I comment out the float calculation part (as noted in the code), I get only zeroes in the ft_all.raw file. The same occurs if I change optimization level from -O3 to -O0.
I've tried countless combinations of all sorts of things, and sometimes it works, sometimes it does not - earlier (with minor modifications to below), the code would only work when optimization was disabled. It may also break if I add something else further down in the file.
My suspicion is that the data transferred by the read()-function may not have been transferred fully (is that possible, even though it returns the correct number of bytes?). This is also the first time I initialize pointers using direct memory adresses, and I have no idea how the compiler reacts to this - perhaps I missed something, here?
I've spent days on this issue now, and I'm getting desperate - I would really appreciate some help on this one! Thanks in advance.
// Clear the top 16M memory for data processing
memset((int *)0x01000000,0x0000,(size_t)SIZE_16M);
/* Prep some pointers for data processing */
int16_t *buffer;
int16_t *buf16I, *buf16Q;
buffer = (int16_t *)(0x1000000);
buf16I = (int16_t *)(0x1600000);
buf16Q = (int16_t *)(0x1680000);
/* Read data from ADC */
int rbytes = read(Sportfd, (int16_t*)buffer, 0x200000);
if (rbytes != 0x200000) {
printf("could not sample data! %X\n",rbytes);
goto end;
} else {
printf("Read %X bytes\n",rbytes);
}
FILE *outfd;
int wbytes;
/* Commenting this region results in all zeroes in ft_all.raw */
float a,b;
int c;
b = 0;
for (c = 0; c < 1000; c++) {
a = c;
b = b+pow(a,3);
}
printf("b is %.2f\n",b);
/* Only 12 LSBs of each 32-bit word is actual data.
* First 20 bits of nothing, then 12 bits I, then 20 bits
* nothing, then 12 bits Q, etc...
* Below, the I and Q parts are scaled with a factor of 16
* and extracted to buf16I and buf16Q.
* */
int32_t *buf32;
buf32 = (int32_t *)buffer;
uint32_t i = 0;
uint32_t n = 0;
while (n < 0x80000) {
buf16I[i] = buf32[n] << 4;
n++;
buf16Q[i] = buf32[n] << 4;
i++;
n++;
}
printf("Saving to /mnt/sd/d/ft_all.raw...");
outfd = fopen("/mnt/sd/d/ft_all.raw", "w+");
if (outfd == NULL) {
printf("Could not open file.\n");
}
wbytes = fwrite((int*)0x1600000, 1, 0x100000, outfd);
fclose(outfd);
if (wbytes < 0x100000) {
printf("wbytes not correct (= %d) \n", (int)wbytes);
}
printf(" done.\n");
Edit: The code seems to work perfectly well if I use read() to read data from a simple file rather than the ADC. This leads me to believe that the rather hacky-looking code when extracting the I and Q parts of the input is working as intended. Inspecting the assembly generated by the compiler confirms this.
I'm trying to get in touch with the developer of the ADC driver to see if he has an explanation of this behaviour.
The ADC is connected through a SPORT, and is opened as such:
sportfd = open("/dev/sport1", O_RDWR);
ioctl(sportfd, SPORT_IOC_CONFIG, spconf);
And here are the options used when configuring the SPORT:
spconf->int_clk = 1;
spconf->word_len = 32;
spconf->serial_clk = SPORT_CLK;
spconf->fsync_clk = SPORT_CLK/34;
spconf->fsync = 1;
spconf->late_fsync = 1;
spconf->act_low = 1;
spconf->dma_enabled = 1;
spconf->tckfe = 0;
spconf->rckfe = 1;
spconf->txse = 0;
spconf->rxse = 1;
A bfin_sport.h file from Analog Devices is also included: https://gist.github.com/tausen/5516954
Update
After a long night of debugging with the previous developer on the project, it turned out the issue was not related to the code shown above at all. As Chris suggested, it was indeed an issue with the SPORT driver and the ADC configuration.
While debugging, this error messaged appeared whenever the data was "broken": bfin_sport: sport ffc00900 status error: TUVF. While this doesn't make much sense in the application, it was clear from printing the data, that something was out of sync: the data in buffer was on the form 0x12000000,0x34000000,... rather than 0x00000012,0x00000034,... whenever the status error was shown. It seems clear then, why buf16I and buf16Q only contained zeroes (since I am extracting the 12 LSBs).
Putting in a few calls to usleep() between stages of ADC initialization and configuration seems to have fixed the issue - I'm hoping it stays that way!