Here is a snippet of my luverrly C code that doesn't work:
... uint8_t volatile *Ready = &PINE; uint8_t volatile *Bus = &PINB; ... while ((*Ready & 0x40) == 0x00) {} // Until READY goes high Count[i] = *Bus; // When gone high, get byte i++ ; // PORTE ^= (1<<2); // Toggle Read while ((*Ready & 0x40) == 0x40) {} // Until READY goes low Count[i] = *Bus; // When gone low, get byte i++ ; // PORTE ^= (1<<2); // Toggle Read ...
Here is a snippet of the assembler version I wrote some time ago to do the same thing. It does work, perfectly adequately:
... BYTE_READ3: in temp, PINE andi temp, $40 ; breq BYTE_READ3 ; ; 'READY' goes high in temp, PINB ; Grab bus st Z+, temp ; Stuff it into some handy SRAM sbi PINE, 2 ; Toggle READ BYTE_READ2: in temp, PINE andi temp, $40 ; brne BYTE_READ2 ; ; 'READY' goes low in temp, PINB ; Grab bus st Z+, temp ; Stuff it into some handy SRAM sbi PINE, 2 ; Toggle READ ...
Now, I'm trying to get all this new program written in C (GCC, with AVR Studio).
I'm declaring my pointers volatile, yet the GCC optimizer still does horrible things to the 'while {}' loops, and it still, when not optimizing at all, winds up putting various bytes in the wrong places in the 'Count' array.
The assembler code is neat and tidy and perfectly reliable. I've never seen it go wrong, and I was highly tempted to try inlining it, but didn't on the grounds that would be also a headache. And besides, I wanted it all in C.
Anyhow, what it is trying to do is communicate with a highly asychronous device (actually, another AVR).
It's setting one pin low, "Read", then waiting for the other to acknowledge having put valid data on the bus "Ready", reading the bus, then toggling "Read" to ask for "More data", and waiting for "Ready" to toggle again.
Note how they both toggle - "Ready" is expected to toggle at some point, and it happens to be pin 6 (0x40) of PortE.
For various reasons (Gone into upon request :wink: ) I think this is a much neater idea than a level-indicated "Data Valid" signal.
In assembler it works fine.
In C? Not so much. Despite making the useful and interesting variables all 'volatile', the GCC optimizer still puts data all wrong. Turning optimization off made for a far larger executable, but it still isn't putting the correct bytes into the correct positions in the array, although it's much closer to correct.
So. What did I do wrong this time? :?:
Any suggestions? Need more info? Let me know.
Scroungre
PS - The disassembler window shows me that what took me six instructions in assembler takes 27 instructions in C. C may be faster to write, but assembler gets it done a lot faster when written... :twisted: