/*************************************************************************** * 16ch RGB 8bit PWM controller * * * * Copyright (C) 2006 - 20011 by Olaf Rempel * * razzor AT kopf MINUS tisch DOT de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; version 2 of the License, * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include #include #include /* * using ATmega32 @8MHz: * Fuse H: 0xD9 (no bootloader, jtag disabled) * Fuse L: 0xD4 (int. 8MHz Osz, fast rising power, no BOD) * * PA0..7 -> COL1..8 * PC0..7 -> COL9..16 * PB0 / PD7(OC2) -> ROW4 * PB1 / PD5(OC1A) -> ROW3 * PB2 / PD4(OC1B) -> ROW2 * PB3(OC0) / PD6 -> ROW1 * PD0 -> RXD * PD1 -> TXD * PD2 -> /RX_TX * PD3 -> /LED */ #define F_CPU 8000000 #include #define ROW1 PORTB1 /* RED */ #define ROW2 PORTB0 /* GREEN */ #define ROW3 PORTB3 /* BLUE */ #define ROW4 PORTB2 /* not used */ #define RXTX PORTD2 #define LED PORTD3 //#define BAUDRATE 115200 #if (BAUDRATE) #define UART_CALC_BAUDRATE(baudRate) (((uint32_t)F_CPU) / (((uint32_t)baudRate)*16) -1) static int uart_putchar(char c, FILE *stream) { if (c == '\n') { loop_until_bit_is_set(UCSRA, UDRE); UDR = '\r'; } loop_until_bit_is_set(UCSRA, UDRE); UDR = c; return 0; } static FILE uart = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_WRITE); #endif /* (BAUDRATE) */ /* 16 values per color */ static uint8_t chan_value[3][16]; /* 16 +1 * 4 values (portA, portC, OCR0, flags) per color */ static uint8_t chan_rawdata[3][17 * 4]; /* used only in ISR */ register uint8_t * pCurrentStep asm("r2"); /* r3:r2 */ /* used to sync ISR and color_update() */ register uint8_t nextColor asm("r4"); /* r4 */ /* worst case: 9+2+12+8+7+13 = 61 clks -> 7.625us @8MHz */ void __attribute__ ((naked)) SIG_OVERFLOW0 (void) { asm volatile( /* save registers 2+1+2+2+2 = 9 */ "push r24 \n\t" "in r24, __SREG__ \n\t" "push r24 \n\t" "push r30 \n\t" "push r31 \n\t" :: ); asm volatile( /* disable outputs 1+1 = 2 */ "out %0, r1 \n\t" /* PORTA = 0x00; */ "out %1, r1 \n\t" /* PORTC = 0x00; */ :: "I" (_SFR_IO_ADDR(PORTA)), "I" (_SFR_IO_ADDR(PORTC)) ); asm volatile( /* switch color and assign pCurrentStep */ "mov r24, %0 \n\t" // 1 1 1 "inc %0 \n\t" /* nextColor++ */ // 2 2 2 "cpi r24, 1 \n\t" // 3 3 3 "brlo L_red%= \n\t" /* if (nextColor < 1) -> red */ // 5 4 4 "breq L_green%= \n\t" /* if (nextColor == 1) -> green */ // - 6 5 "clr %0 \n\t" /* nextColor = 0; */ // - - 6 "ldi r24, %8 \n\t" /* PORTB = (1< 4.5us @ 8MHz */ void __attribute__ ((naked)) SIG_OUTPUT_COMPARE0 (void) { asm volatile( /* save registers 2+1+2+2+2 = 9 */ "push r24 \n\t" "in r24, __SREG__ \n\t" "push r24 \n\t" "push r30 \n\t" "push r31 \n\t" :: ); asm volatile( /* load table values 1+1+1+1+1+1+1+1+1 = 9 */ "movw r30, %0 \n\t" "ld r24, z+ \n\t" "out %1, r24 \n\t" /* PORTA = *pCurrentStep++; */ "ld r24, z+ \n\t" "out %2, r24 \n\t" /* PORTC = *pCurrentStep++; */ "ld r24, z+ \n\t" "out %3, r24 \n\t" /* OCR0 = *pCurrentStep++; */ "ld r24, z+ \n\t" "movw %0, r30 \n\t" :: "r" (pCurrentStep), "I" (_SFR_IO_ADDR(PORTA)), "I" (_SFR_IO_ADDR(PORTC)), "I" (_SFR_IO_ADDR(OCR0)) ); asm volatile( /* check if IRQ must be disabled 1+1+1+1+1 = 3/5 */ "or r24, r24 \n\t" /* if (!(*pCurrentStep++)) { */ "brne L_skip%= \n\t" "in r24, %0 \n\t" /* TIMSK &= ~(1<> 8) & 0xFF); /* PORTC */ /* previous step needs timervalue and enable IRQ */ *(pData++ -4) = min_value -0; /* OCR0 */ /* FIXME: -1 ? */ *(pData++ -4) = 0x01; /* flags */ } index++; } /* fill all remaining slots */ while (index < 16) { /* repeat enabled outputs */ *pData++ = (chan_used & 0xFF); /* PORTA */ *pData++ = ((chan_used >> 8) & 0xFF); /* PORTC */ /* previous step was last one (no timevalue / disable IRQ) */ *(pData++ -4) = 0x00; /* OCR0 */ *(pData++ -4) = 0x00; /* flags */ index++; } /* first slot/init: enable only channels that are > 0 */ pData = pDataStart; *pData++ = (chan_init & 0xFF); /* PORTA */ *pData++ = ((chan_init >> 8) & 0xFF); /* PORTC */ } #if (BAUDRATE) void print_values(uint8_t *data) { uint8_t i; for (i = 0; i < 17; i++) { fprintf(&uart, "%2d: %02X %02X %02X %02X\n", i, data[(i<<2)], data[(i<<2) +1], data[(i<<2) +2], data[(i<<2) +3]); if (data[(i<<2) +3] == 0x00) break; } } #else #define print_values(data) #endif /* (BAUDRATE) */ int main(void) { /* 16 PWM Outputs */ PORTA = 0x00; DDRA = 0xFF; PORTB = 0x00; DDRB = (1<>8) & 0xFF; UBRRL = (UART_CALC_BAUDRATE(BAUDRATE) & 0xFF); /* enable usart with 8n1 */ UCSRB = (1<> 8) { case 6: ramp = 0x0000; /* no break */ case 0: /* red: on, green: ramp up, blue: off */ color[0] = 0xFF; color[1] = ramp & 0xFF; color[2] = 0x00; break; case 1: /* red: ramp down, green: on, blue:off */ color[0] = 0xFF - (ramp & 0xFF); color[1] = 0xFF; color[2] = 0x00; break; case 2: /* red: off, green: on, blue: ramp up */ color[0] = 0x00; color[1] = 0xFF; color[2] = (ramp & 0xFF); break; case 3: /* red: off, green: ramp down: blue: on */ color[0] = 0x00; color[1] = 0xFF - (ramp & 0xFF); color[2] = 0xFF; break; case 4: /* red: ramp up, green: off, blue: on */ color[0] = (ramp & 0xFF); color[1] = 0x00; color[2] = 0xFF; break; case 5: /* red: on, green: off, blue: ramp down */ color[0] = 0xFF; color[1] = 0x00; color[2] = 0xFF - (ramp & 0xFF); break; } uint8_t i, j; for (i = 0; i < 16; i++) { for (j = 0; j < 3; j++) { #if 0 if (x == i) { chan_value[j][i] = color[j]; } else if (chan_value[j][i] > 0) { uint8_t tmp = (chan_value[j][i] >> 5); chan_value[j][i] -= (tmp > 0) ? tmp : 1; } #else chan_value[j][i] = color[j]; #endif } } } return 0; }