Permalink
Browse files

Clean start

Program Memory Usage  : 3048 bytes   74.4 % Full
Data Memory Usage   : 79 bytes   30.9 % Full
Time in Refresh (min/max): 153us/174us

Starting with very clean and readable, but non-optimized code.
  • Loading branch information...
1 parent 799e737 commit e504f0ca18015cded76e5900ab0f04d0d8292831 @bigjosh committed Nov 30, 2013
Showing with 63 additions and 74 deletions.
  1. +63 −74 Atmel Studio/Candle0005.c
@@ -180,9 +180,7 @@ static inline void nextFrame(void) {
// Time to display the next frame in the animation...
// copy the next frame from program memory (candel_bitstream[]) to the RAM frame buffer (fda[])
-
-
-
+
static byte const *candleBitstremPtr; // next byte to read from the bitstream in program memory
static byte workingByte; // current working byte
@@ -267,54 +265,55 @@ static inline void nextFrame(void) {
static byte const rowDirectionBits = 0b01010101; // 0=row goes low, 1=Row goes high
-static byte const portBRowBits[ROWS] = {_BV(0),_BV(0),_BV(2),_BV(2),_BV(4),_BV(4),_BV(6),_BV(6) };
+PROGMEM static byte const portBRowBits[ROWS] = {_BV(0),_BV(0),_BV(2),_BV(2),_BV(4),_BV(4),_BV(6),_BV(6) };
+PROGMEM static byte const portDRowBits[ROWS] = { 0, 0, 0, 0, 0, 0, 0, 0 };
-#ifndef ALL_PORTD_ROWS_ZERO
- static byte const portDRowBits[ROWS] = { 0, 0, 0, 0, 0, 0, 0, 0 };
-#endif
-
// Note that col is always opposite of row so we don't need colDirectionBits
-static byte const portBColBits[COLS] = {_BV(7),_BV(5),_BV(3), _BV(1), 0};
-static byte const portDColBits[COLS] = { 0, 0, 0, 0,_BV(6)};
+PROGMEM static byte const portBColBits[COLS] = {_BV(7),_BV(5),_BV(3), _BV(1), 0};
+PROGMEM static byte const portDColBits[COLS] = { 0, 0, 0, 0,_BV(6)};
#define REFRESH_PER_FRAME ( REFRESH_RATE / FRAME_RATE ) // How many refreshes before we trigger the next frame to be drawn?
byte refreshCount =REFRESH_PER_FRAME+1;
+
+
+
// Do a single full screen refresh
// call nextframe() to decode next frame into buffer afterwards if it is time
+// This version will work with any combination of row/col bits
-static inline void refreshScreen(void)
+
+
+static inline void refreshScreenClean(void)
{
- #ifdef TIMECHECK
+ #ifdef TIMECHECK
DDRA = _BV(0)|_BV(1); // Set PORTA0 for output. Use OR because it compiles to single SBI instruction
PORTA |=_BV(0); // twiddle A0 bit for oscilloscope timing
#endif
-
+
byte *fdaptr = fda; // Where are we in scanning through the FDA?
byte rowDirectionBitsRotating = rowDirectionBits; // Working space for rowDirections bits that we shift down once for each row
- // Bit 0 will be bit for the current row.
- // TODO: in ASM, would could shift though the carry flag and jmp based on that and save a bit test
+ // Bit 0 will be bit for the current row.
+ // TODO: in ASM, would could shift though the carry flag and jmp based on that and save a bit test
+
-
for( byte int_y = 0 ; int_y < FDA_Y_MAX ; int_y++ ) {
- byte portBRowBitsCache = portBRowBits[int_y];
+ byte portBRowBitsCache = pgm_read_byte_near(portBRowBits+int_y);
+
+ byte portDRowBitsCache = pgm_read_byte_near(portDRowBits+int_y);
- #ifndef ALL_PORTD_ROWS_ZERO
- byte portDRowBitsCache = portDRowBits[int_y];
- #endif
-
for( byte int_x = 0 ; int_x < FDA_X_MAX ; int_x++) {
-
+
// get the brightness of the current LED
register byte b = *( fdaptr++ ); // Want this in a register because later we will loop on it and want the loop entrance to be quick
-
+
// If the LED is off, then don't need to do anything since all LEDs are already off all the time except for a split second inside this routine....
if (b>0) {
@@ -328,92 +327,82 @@ static inline void refreshScreen(void)
PORTB = portBRowBitsCache;
- #ifndef ALL_PORTD_ROWS_ZERO
- PORTD = portDRowBitsCache;
- #else
- PORTD = 0;
- #endif
+ PORTD = portDRowBitsCache;
// Only need to set the correct bits in PORTB and PORTD to drive the row high (col bit will get set to 0)
- ddrbt = portBRowBitsCache | portBColBits[int_x] ; // enable output for the Row pins to drive high, also enable output for col pins which are zero so will go low
-
- #ifndef ALL_PORTD_ROWS_ZERO
- ddrdt = portDRowBitsCache | portDColBits[int_x] ;
- #else
- ddrdt = portDColBits[int_x];
- #endif
+ ddrbt = portBRowBitsCache | pgm_read_byte_near(portBColBits+int_x) ; // enable output for the Row pins to drive high, also enable output for col pins which are zero so will go low
+
+ ddrdt = portDRowBitsCache | pgm_read_byte_near(portDColBits+int_x) ;
} else { // row goes low, cols go high....
- PORTB = portBColBits[int_x];
- PORTD = portDColBits[int_x];
+ PORTB = pgm_read_byte_near(portBColBits+int_x);
+ PORTD = pgm_read_byte_near(portDColBits+int_x);
ddrbt = PORTB | portBRowBitsCache; // enable output for the col pins to drive high, also enable output for row pins which are zero so will go low
- #ifndef ALL_PORTD_ROWS_ZERO
- ddrdt = PORTD | portDRowBitsCache;
- #else
- ddrdt = PORTD;
- #endif
-
+ ddrdt = PORTD | portDRowBitsCache;
+
}
- // Now comes the business of Actually turning on the LED.
-
- // This is the tightest loop possible - I can't figure out how to do it in C
-
+ // Now comes the business of Actually turning on the LED.
+
+ // This is the tightest loop possible - I can't figure out how to do it in C
+
//while (b--) asm volatile (""); //does not work because it generates a strange RJMP +0 loop preamble
//_delay_loop_1( b ); // DOes not work becuase it pathalogically loads b into a register
-
+
+
asm volatile (
- // TODO: Do actual visual test to make sure that actual brightness is linear and smooth with this algorthim
- // Might not be because this does not take into account delay of loop branching. It would take at least 5 lines of
- // code to get this timing exactly right by special casing out b=1 and b=2, and then dividing higher numbers to account for the branch cost
- // would be better to have this already accounted into the precomputed brightness->dutycycle map.
+ // TODO: Do actual visual test to make sure that actual brightness is linear and smooth with this algorthim
+ // Might not be because this does not take into account delay of loop branching. It would take at least 5 lines of
+ // code to get this timing exactly right by special casing out b=1 and b=2, and then dividing higher numbers to account for the branch cost
+ // would be better to have this already accounted into the precomputed brightness->dutycycle map.
+
+ "OUT %0,%1 \n\t" // DO DDRD first because in current config it will never actually have both pins so LED can't turn on (not turn of DDRB)
+ "OUT %2,%3 \n\t" // Ok, LED is on now!
+ "L_%=:dec %4 \n\t"
+// "BRNE L_%= \n\t"
+ "OUT %2,__zero_reg__ \n\t" // Do DDRB first since this will definitely turn off the LED
+ "OUT %0,__zero_reg__ \n\t"
+
+ : : "I" (_SFR_IO_ADDR(DDRD)) , "r" (ddrdt) , "I" (_SFR_IO_ADDR(DDRB)) , "r" (ddrbt) , "r" (b)
- "OUT %0,%1 \n\t" // DO DDRD first because in current config it will never actually have both pins so LED can't turn on (not turn of DDRB)
- "OUT %2,%3 \n\t" // Ok, LED is on now!
- "L_%=:dec %4 \n\t"
- "BRNE L_%= \n\t"
- "OUT %2,__zero_reg__ \n\t" // Do DDRB first since this will definitely turn off the LED
- "OUT %0,__zero_reg__ \n\t"
-
- : : "I" (_SFR_IO_ADDR(DDRD)) , "r" (ddrdt) , "I" (_SFR_IO_ADDR(DDRB)) , "r" (ddrbt) , "r" (b)
-
);
}
-
+
}
rowDirectionBitsRotating >>= 1; // Shift bits down so bit 0 has the value for the next row
-
+
}
#ifdef TIMECHECK
PORTA &= ~_BV(0);
#endif
-
+
refreshCount--;
-
+
if (refreshCount == 0 ) { // step to next frame in the animation sequence?
- refreshCount=REFRESH_PER_FRAME+1;
-
- // TODO: this diagnostic screen generator costs 42 bytes. Can we make it smaller or just get rid of it?
-
- nextFrame();
-
+ refreshCount=REFRESH_PER_FRAME+1;
+
+ // TODO: this diagnostic screen generator costs 42 bytes. Can we make it smaller or just get rid of it?
+
+ nextFrame();
+
}
-
-
+
+
}
+
void init0 (void) __attribute__ ((naked)) __attribute__ ((section (".init0")));
// This code will be run immedeately on reset, before any initilization or main()
@@ -473,7 +462,7 @@ int main(void)
static inline void userWakeRoutine(void) {
- refreshScreen();
+ refreshScreenClean();
}

0 comments on commit e504f0c

Please sign in to comment.