Probably a pointer issue but not sure why - c

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];

Related

Keil uVision - Atmel SAM3U Read Unique Identifier

I've been trying to read the Unique Identifier (UID) from a Atmel SAM3U MCU, but it's proven more difficult than it needs to be to make it happen. Does anyone have any examples or can suggest how to read it properly? Whenever I do, I wait in a do while loop (like the documentation states) for the EEFC (Flash ROM) status register to change states, but it never does so the MCU is then stuck in a loop.
Here is the code I'm using
// must run this from SRAM
__attribute__((section(".ARM.__at_0x20080000"))) void Get_Unique_ID(unsigned int *pdwUniqueID)
{
Efc *p_efc;
unsigned int status;
// clear the array
pdwUniqueID[0] = 0;
pdwUniqueID[1] = 0;
pdwUniqueID[2] = 0;
pdwUniqueID[3] = 0;
// send the Start Read Unique Identifier command (STUI) by writing the Flash Command Register with the STUI command
p_efc->EEFC_FCR = EEFC_FCR_FKEY_PASSWD | EEFC_FCR_FCMD_STUI;
// wait for the Flash Programming Status Register (EEFC_FSR) to fall
do { status = p_efc->EEFC_FSR; }
while ((status & EEFC_FSR_FRDY) == EEFC_FSR_FRDY);
// the Unique Identifier is located in the first 128 bits of the Flash memory mapping
pdwUniqueID[0] = *(unsigned int *)IFLASH0_ADDR;
pdwUniqueID[1] = *(unsigned int *)(IFLASH0_ADDR + 4);
pdwUniqueID[2] = *(unsigned int *)(IFLASH0_ADDR + 8);
pdwUniqueID[3] = *(unsigned int *)(IFLASH0_ADDR + 12);
// to stop the Unique Identifier mode, the user needs to send the Stop Read unique Identifier
// command (SPUI) by writing the Flash Command Register with the SPUI command
p_efc->EEFC_FCR = EEFC_FCR_FKEY_PASSWD | EEFC_FCR_FCMD_SPUI;
// when the Stop Read Unique Unique Identifier command (SPUI) has been performed
// the FRDY bit in the Flash Programming Status Register (EEFC_FSR) rises
do { status = p_efc->EEFC_FSR; }
while ((status & EEFC_FSR_FRDY) != EEFC_FSR_FRDY);
}
Note that __attribute__((section(".ARM.__at_0x20080000"))) isn't the best method to dynamically assign this function to SRAM via the linker and any suggestions on how to make it more dynamic would be appreciated.
SOLVED The problem was the chips I had were fake so SAM-BA was returning whatever was at the SRAM buffer address it specified. It's a bug in SAM-BA since if it received 0x00000000, it should give an error or warning message and then stop reading. Do not buy fake chips from China!
Thanks.
I don't believe p_efc is correctly initialized.
You create a pointer to a Efc datastructure which thus points to something.
You then write something to somewhere and are expect it to work.
Efc *p_efc;
p_efc->EEFC_FCR = EEFC_FCR_FKEY_PASSWD | EEFC_FCR_FCMD_STUI;
My guess would be that you need to intialize it to the correct EEFC base address. The datasheet has the following to say:
The SAM3U4 (256 Kbytes internal Flash
version) embeds two EEFC (EEFC0 for Flash0 and EEFC1 for Flash1)
whereas the SAM3U2/1 embeds one EEFC.
So depending on your MCU version you need to address EEFC0 or EEFC1. I'm assuming that you use libopencm3 but this will work for any other library. Look for the EEFC location define. Following the defines/files/links we get to this page, it tells us to point our Efc pointer to EEFC0_BASE or EEFC1_BASE. I would advise you to use the EEFC0 and EEFC1 defines though as it makes your code portabler.
So your code should work if your Efc is located in EEFC0 if you do:
Efc *p_efc = EEFC0;

Uart receives correct Bytes but in chaotic order

Using Atmel studio 7, with STK600 and 32UC3C MCU
I'm pulling my hair over this.
I'm sending strings of a variable size over UART once every 5 seconds. The String consists of one letter as opcode, then two chars are following that tell the lenght of the following datastring (without the zero, there is never a zero at the end of any of those strings). In most cases the string will be 3 chars in size, because it has no data ("p00").
After investigation I found out that what supposed to be "p00" was in fact "0p0" or "00p" or (only at first try after restarting the micro "p00"). I looked it up in the memory view of the debugger. Then I started hTerm and confirmed that the data was in fact "p00". So after a while hTerm showed me "p00p00p00p00p00p00p00..." while the memory of my circular uart buffer reads "p000p000p0p000p0p000p0p0..."
edit: Actually "0p0" and "00p" are alternating.
The baud rate is 9600. In the past I was only sending single letters. So everything was running well.
This is the code of the Receiver Interrupt:
I tried different variations in code that were all doing the same in a different way. But all of them showed the exact same behavior.
lastWebCMDWritePtr is a uint8_t* type and so is lastWebCMDRingstartPtr.
lastWebCMDRingRXLen is a uint8_t type.
__attribute__((__interrupt__))
void UartISR_forWebserver()
{
*(lastWebCMDWritePtr++) = (uint8_t)((&AVR32_USART0)->rhr & 0x1ff);
lastWebCMDRingRXLen++;
if(lastWebCMDWritePtr - lastWebCMDRingstartPtr > lastWebCMDRingBufferSIZE)
{
lastWebCMDWritePtr = lastWebCMDRingstartPtr;
}
// Variation 2:
// advanceFifo((uint8_t)((&AVR32_USART0)->rhr & 0x1ff));
// Variation 3:
// if(usart_read_char(&AVR32_USART0, getReadPointer()) == USART_RX_ERROR)
// {
// usart_reset_status(&AVR32_USART0);
// }
//
};
I welcome any of your ideas and advices.
Regarts Someo
P.S. I put the Atmel studio tag in case this has something to do with the myriad of debugger bugs of AS.
For a complete picture you would have to show where and how lastWebCMDWritePtr, lastWebCMDRingRXLen, lastWebCMDRingstartPtr and lastWebCMDRingBufferSIZE are used elsewhere (on the consuming side)
Also I would first try a simpler ISR with no dependencies to other software modules to exclude a hardware resp. register handling problem.
Approach:
#define USART_DEBUG
#define DEBUG_BUF_SIZE 30
__attribute__((__interrupt__))
void UartISR_forWebserver()
{
uint8_t rec_byte;
#ifdef USART_DEBUG
static volatile uint8_t usart_debug_buf[DEBUG_BUF_SIZE]; //circular buffer for debugging
static volatile int usart_debug_buf_index = 0;
#endif
rec_byte = (uint8_t)((&AVR32_USART0)->rhr & 0x1ff);
#ifdef USART_DEBUG
usart_debug_buf_index = usart_debug_buf_index % DEBUG_BUF_SIZE;
usart_debug_buf[usart_debug_buf_index] = rec_byte;
usart_debug_buf_index++
if (!(usart_debug_buf_index < DEBUG_BUF_SIZE)) {
usart_debug_buf_index = 0; //candidate for a breakpoint to see what happened in the past
}
#endif
//uart_recfifo_enqueue(rec_byte);
};

AVR gcc, weird array behaviour

it's the first time I see something like this. I'm starting to suspect it's a hardware fault.
whenever I try to send the contents of array "test" and that array is larger than 4 elements or I initialize all elements in the declaration it contains 0xff instead of values I try to initialise with.
this works fine. when I read values from the array in while(sending them to the lcd and uart) both readouts are consistent with test values:
uint8_t i=0;
uint8_t test[4] = {1,2,3,4};
while(i<5){
GLCD_WriteData(test[i]);
USART_Transmit(test[i]);
i++;
}
this doesn't, it returns 0xff instead of test[i] value:
uint8_t i=0;
uint8_t test[5] = {1,2,3,4,5};
while(i<5){
GLCD_WriteData(test[i]);
USART_Transmit(test[i]);
i++;
}
but this works! it returns proper values
uint8_t i=0;
uint8_t test[6] = {1,2,3,4,5};
while(i<5){
GLCD_WriteData(test[i]);
USART_Transmit(test[i]);
i++;
}
this also works:
uint8_t i=0;
uint8_t test[5];
test[0]=1;
test[1]=2;
test[2]=3;
test[3]=4;
test[4]=5;
while(i<5){
GLCD_WriteData(test[i]);
USART_Transmit(test[i]);
i++;
}
it works fine when compiled on linux
I swapped out an mcu for a different one and it works the way it should. must be an hardware problem
In first example you are going out of bounds of array test[4]. You are running while 5 times, when array has only 4 items length.
I think your problem is that you're overloading the USART. I assume that GLCD_WriteData() is VERY quick, and that USART_Transmit() buffers the character for transmission and then quickly returns. I don't know your hardware, so I can't tell - but a four-character buffer for a USART sounds reasonable.
Your five-character examples don't work because the actual character that you're trying to transmit is lost - so it puts an 0xFF in instead. You need to check the state of the USART buffer and wait for it to show that space is available (note NOT empty - that'd be inefficient!).
In the 8250 and 16450 UART chips there are two status bits:
TSRE says that the Transmit Shift Register is Empty;
THRE says that the Transmit Holding Register is Empty.
THRE can be set even when TSRE isn't - it's busy. I'd test TSRE and not send the next character until there's room - or set up a buffer and an interrupt handler.
If it's not the I/O hardware, then the only other thing that I can think of is the compiler is producing incorrect code. What is the exact declaration of USART_Transmit()? Does it expect a uint8_t? Or something else, like an int (for some reason)?
If it's something else, like int, please try the following code:
while(i<5){
int c = test[i]; // Whatever USART_Transmit wants
GLCD_WriteData(test[i]);
USART_Transmit(c);
i++;
} // while
If that always works, then you've got a compiler problem, not a hardware problem.
EDIT: Code for USART_Transmit() provided:
void USART_Transmit( uint8_t data ) {
//Wait for empty transmit buffer
while( !( UCSR0A & (1<<UDRE0)) );
//Put data into buffer, sends the data
UDR0 = data;
}
You've got something better than JTAG - you've got an LCD display! Although I don't know how many characters it has, or how long it takes to transmit a character...
You could try something like:
char Hex(uint8_t nibble) {
return nibble<10 ?
'0'+nibble :
'A'+nibble-10;
} // Hex
...
void Send(uint8_t c) {
uint8_t s;
UDR0 = c; // Send character NOW: don't wait!
do {
s = UCSR0A; // Get current USART state
//s = UCSR0A & (1<<UDRE0); // Or this: isolate ready bit...
GLCD_WriteData('x');
GLCD_WriteData(Hex(s >> 4)); // Write state-hi hex
GLCD_WriteData(Hex(s & 0xF)); // Write state-lo hex
} while (!(s & (1<<UDRE0))); // Until is actually ready
} // Send(c)
...
Send('A');
Send('B');
Send('C');
Assuming that UDRE0 is 3, then that code will result in a sequence like x00x00x00x00x00x08x00x00x00x00x08x00x00x00x08 if it is working. If it produces x08x08x08 then you've got a stuck UCSR0A bit, and it's hardware.
Old question, but giving my feedback since this is the first place I got sent while searching solution for same issue, getting even exact same results with the code samples in original question.
For me it was a bad Makefile that caused some sections to be left out by avr-objcopy as far as I know.
For example in my case, the original parameters for building my sample hex that were causing this issue:
${OBJCOPY} -j .text -O ihex led.elf led.hex
What worked a bit better:
${OBJCOPY} -O ihex -R .eeprom led.elf led.hex

--fill command on PIC32MX boot flash memory

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

C on embedded system w/ linux kernel - mysterious adc read issue

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!

Resources