This commit is contained in:
Olaf Rempel 2012-02-11 14:00:34 +01:00
parent 5465febd59
commit d27cd42955
7 changed files with 177 additions and 73 deletions

View File

@ -1,7 +1,7 @@
PRG = 16ch_pwm PRG = rgb16mpm
OBJ = main.o OBJ = main.o
MCU_TARGET = atmega32 MCU_TARGET = atmega32
OPTIMIZE = -O2 OPTIMIZE = -Os
DEFS = DEFS =
LIBS = LIBS =

BIN
eagle/rgb16mpm-bot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

BIN
eagle/rgb16mpm-sch.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

BIN
eagle/rgb16mpm-top.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

BIN
eagle/rgb16mpm.brd Normal file

Binary file not shown.

BIN
eagle/rgb16mpm.sch Normal file

Binary file not shown.

246
main.c
View File

@ -1,7 +1,7 @@
/*************************************************************************** /***************************************************************************
* 16ch RGB 8bit PWM controller * * 16ch RGB 8bit PWM controller *
* * * *
* Copyright (C) 2006 - 20011 by Olaf Rempel * * Copyright (C) 2011 - 2012 by Olaf Rempel *
* razzor AT kopf MINUS tisch DOT de * * razzor AT kopf MINUS tisch DOT de *
* * * *
* This program is free software; you can redistribute it and/or modify * * This program is free software; you can redistribute it and/or modify *
@ -20,6 +20,7 @@
***************************************************************************/ ***************************************************************************/
#include <avr/io.h> #include <avr/io.h>
#include <avr/interrupt.h> #include <avr/interrupt.h>
#include <avr/wdt.h>
#include <stdio.h> #include <stdio.h>
@ -30,10 +31,10 @@
* *
* PA0..7 -> COL1..8 * PA0..7 -> COL1..8
* PC0..7 -> COL9..16 * PC0..7 -> COL9..16
* PB0 / PD7(OC2) -> ROW4 * PB0 / PD7(OC2) -> ROW4 (OC2 not used)
* PB1 / PD5(OC1A) -> ROW3 * PB1 / PD5(OC1A) -> ROW3 (OC1A not used)
* PB2 / PD4(OC1B) -> ROW2 * PB2 / PD4(OC1B) -> ROW2 (OC1B not used)
* PB3(OC0) / PD6 -> ROW1 * PB3(OC0) / PD6 -> ROW1 (OC0 not used)
* PD0 -> RXD * PD0 -> RXD
* PD1 -> TXD * PD1 -> TXD
* PD2 -> /RX_TX * PD2 -> /RX_TX
@ -41,7 +42,6 @@
*/ */
#define F_CPU 8000000 #define F_CPU 8000000
#include <util/delay.h> #include <util/delay.h>
#define ROW1 PORTB1 /* RED */ #define ROW1 PORTB1 /* RED */
@ -49,43 +49,47 @@
#define ROW3 PORTB3 /* BLUE */ #define ROW3 PORTB3 /* BLUE */
#define ROW4 PORTB2 /* not used */ #define ROW4 PORTB2 /* not used */
#define RXTX PORTD2 #define RXTX PORTD2 /* RS485 TX enable */
#define LED PORTD3 #define LED PORTD3
//#define BAUDRATE 115200 /* running without mpmboot? */
#define STANDALONE 0
#if (STANDALONE)
#define OSCCAL 0xAA
#define BAUDRATE 115200
#define MPM_ADDRESS 0x11
#if (BAUDRATE)
#define UART_CALC_BAUDRATE(baudRate) (((uint32_t)F_CPU) / (((uint32_t)baudRate)*16) -1) #define UART_CALC_BAUDRATE(baudRate) (((uint32_t)F_CPU) / (((uint32_t)baudRate)*16) -1)
#endif /* STANDALONE */
static int uart_putchar(char c, FILE *stream) const static uint8_t versioninfo[16] = "rgb16mpm v0.99";
{
if (c == '\n') {
loop_until_bit_is_set(UCSRA, UDRE);
UDR = '\r';
}
loop_until_bit_is_set(UCSRA, UDRE); #define CMD_WAIT 0x00
UDR = c; #define CMD_SWITCH_MODE 0x01
return 0; #define CMD_GET_VERSION 0x02
} // #define CMD_GET_CHIPINFO 0x03
// #define CMD_READ_MEMORY 0x11
static FILE uart = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_WRITE); // #define CMD_WRITE_MEMORY 0x12
#endif /* (BAUDRATE) */ #define CMD_WRITE_COLOR 0x81
#define CMD_WRITE_RAW_COLOR 0x82
#define CMD_READ_RAW_COLOR 0x83
#define CMD_WRITE_CONFIG 0x81
/* 16 values per color */ /* 16 values per color */
static uint8_t chan_value[3][16]; static uint8_t chan_value[3][16];
/* 16 +1 * 4 values (portA, portC, OCR0, flags) per color */ /* (16 +1) * 4 values (portA, portC, OCR0, flags) per color */
static uint8_t chan_rawdata[3][17 * 4]; static uint8_t chan_rawdata[3][17 * 4];
/* used only in ISR */ /* used only in softpwm ISRs */
register uint8_t * pCurrentStep asm("r2"); /* r3:r2 */ register uint8_t * pCurrentStep asm("r2"); /* r3:r2 */
/* used to sync ISR and color_update() */ /* used to sync softpwm ISRs and color_update() */
register uint8_t nextColor asm("r4"); /* r4 */ register uint8_t nextColor asm("r4"); /* r4 */
/* worst case: 9+2+12+8+7+13 = 61 clks -> 7.625us @8MHz */ /* worst case: 9+2+12+8+7+13 = 61 clks -> 7.625us @8MHz */
void __attribute__ ((naked)) SIG_OVERFLOW0 (void) ISR(TIMER0_OVF_vect, ISR_NAKED)
{ {
asm volatile( asm volatile(
/* save registers 2+1+2+2+2 = 9 */ /* save registers 2+1+2+2+2 = 9 */
@ -106,30 +110,29 @@ void __attribute__ ((naked)) SIG_OVERFLOW0 (void)
); );
asm volatile( asm volatile(
/* switch color and assign pCurrentStep */ /* switch color and assign pCurrentStep */ // R G B
"mov r24, %0 \n\t" // 1 1 1 "mov r24, %0 \n\t" // 1 1 1
"inc %0 \n\t" /* nextColor++ */ // 2 2 2 "inc %0 \n\t" /* nextColor++ */ // 2 2 2
"cpi r24, 1 \n\t" // 3 3 3 "cpi r24, 1 \n\t" // 3 3 3
"brlo L_red%= \n\t" /* if (nextColor < 1) -> red */ // 5 4 4 "brlo L_red%= \n\t" /* if (nextColor < 1) -> red */ // 5 4 4
"breq L_green%= \n\t" /* if (nextColor == 1) -> green */ // - 6 5 "breq L_green%= \n\t" /* if (nextColor == 1) -> green */ // - 6 5
"clr %0 \n\t" /* nextColor = 0; */ // - - 6 "clr %0 \n\t" /* nextColor = 0; */ // - - 6
"ldi r24, %8 \n\t" /* PORTB = (1<<ROW4); */ // - - 7 "ldi r24, %7 \n\t" /* PORTB = (1<<ROW4); */ // - - 7
"ldi r30, lo8(%4) \n\t" /* pCurrentStep = &rawdata[2]; */ // - - 8 "ldi r30, lo8(%3) \n\t" /* pCurrentStep = &rawdata[2]; */ // - - 8
"ldi r31, hi8(%4) \n\t" // - - 9 "ldi r31, hi8(%3) \n\t" // - - 9
"rjmp L_end%= \n\t" // - - 11 "rjmp L_end%= \n\t" // - - 11
"L_red%=: \n\t" /* red: */ "L_red%=: \n\t" /* red: */
"ldi r24, %6 \n\t" /* PORTB = (1<<ROW1); */ // 6 - - "ldi r24, %5 \n\t" /* PORTB = (1<<ROW1); */ // 6 - -
"ldi r30, lo8(%2) \n\t" /* pCurrentStep = &rawdata[0]; */ // 7 - - "ldi r30, lo8(%1) \n\t" /* pCurrentStep = &rawdata[0]; */ // 7 - -
"ldi r31, hi8(%2) \n\t" // 8 - - "ldi r31, hi8(%1) \n\t" // 8 - -
"rjmp L_end%= \n\t" // 10 - - "rjmp L_end%= \n\t" // 10 - -
"L_green%=: \n\t" /* green: */ "L_green%=: \n\t" /* green: */
"ldi r24, %7 \n\t" /* PORTB = (1<<ROW2); */ // - 7 - "ldi r24, %6 \n\t" /* PORTB = (1<<ROW2); */ // - 7 -
"ldi r30, lo8(%3) \n\t" /* pCurrentStep = &rawdata[1]; */ // - 8 - "ldi r30, lo8(%2) \n\t" /* pCurrentStep = &rawdata[1]; */ // - 8 -
"ldi r31, hi8(%3) \n\t" // - 9 - "ldi r31, hi8(%2) \n\t" // - 9 -
"L_end%=: \n\t" "L_end%=: \n\t"
"out %5, r24 \n\t" /* set PORTB */ // 11 10 12 "out %4, r24 \n\t" /* set PORTB */ // 11 10 12
:: "r" (nextColor), :: "r" (nextColor),
"r" (pCurrentStep),
"i" (&chan_rawdata[0]), /* RED */ "i" (&chan_rawdata[0]), /* RED */
"i" (&chan_rawdata[1]), /* GREEN */ "i" (&chan_rawdata[1]), /* GREEN */
"i" (&chan_rawdata[2]), /* BLUE */ "i" (&chan_rawdata[2]), /* BLUE */
@ -184,7 +187,7 @@ void __attribute__ ((naked)) SIG_OVERFLOW0 (void)
} }
/* worst case: 9+9+5+13 = 36 clks -> 4.5us @ 8MHz */ /* worst case: 9+9+5+13 = 36 clks -> 4.5us @ 8MHz */
void __attribute__ ((naked)) SIG_OUTPUT_COMPARE0 (void) ISR(TIMER0_COMP_vect, ISR_NAKED)
{ {
asm volatile( asm volatile(
/* save registers 2+1+2+2+2 = 9 */ /* save registers 2+1+2+2+2 = 9 */
@ -237,7 +240,7 @@ void __attribute__ ((naked)) SIG_OUTPUT_COMPARE0 (void)
); );
} }
/* calc chan_valueX => chan_rawdataX */
static void calculate_timer_values(uint8_t *value, uint8_t *pDataStart) static void calculate_timer_values(uint8_t *value, uint8_t *pDataStart)
{ {
uint8_t *pData = pDataStart +4; /* skip first entry (init) */ uint8_t *pData = pDataStart +4; /* skip first entry (init) */
@ -285,7 +288,7 @@ static void calculate_timer_values(uint8_t *value, uint8_t *pDataStart)
*pData++ = ((chan_used >> 8) & 0xFF); /* PORTC */ *pData++ = ((chan_used >> 8) & 0xFF); /* PORTC */
/* previous step needs timervalue and enable IRQ */ /* previous step needs timervalue and enable IRQ */
*(pData++ -4) = min_value -0; /* OCR0 */ /* FIXME: -1 ? */ *(pData++ -4) = min_value; /* OCR0 */
*(pData++ -4) = 0x01; /* flags */ *(pData++ -4) = 0x01; /* flags */
} }
@ -311,55 +314,149 @@ static void calculate_timer_values(uint8_t *value, uint8_t *pDataStart)
*pData++ = ((chan_init >> 8) & 0xFF); /* PORTC */ *pData++ = ((chan_init >> 8) & 0xFF); /* PORTC */
} }
#if (BAUDRATE) static uint8_t rx_cmd;
void print_values(uint8_t *data) static uint16_t rx_bcnt = 0xFF;
static uint16_t rx_length;
static uint8_t tx_cmd;
static uint8_t tx_cause;
static uint16_t tx_length;
static uint16_t tx_bcnt;
ISR(USART_RXC_vect)
{ {
uint8_t i; uint8_t data = UDR;
sei();
for (i = 0; i < 17; i++) { if (rx_bcnt == 0xFF) {
fprintf(&uart, "%2d: %02X %02X %02X %02X\n", i, /* MPM address stored in TWI address register by bootloader */
data[(i<<2)], data[(i<<2) +1], if (data == TWAR) {
data[(i<<2) +2], data[(i<<2) +3]); UCSRA &= ~(1<<MPCM);
rx_bcnt = 0;
}
if (data[(i<<2) +3] == 0x00) } else {
break; if (rx_bcnt == 0) {
rx_cmd = data;
} else if ((rx_bcnt == 1) || (rx_bcnt == 2)) {
rx_length = (rx_length << 8) | data;
} else if ((rx_bcnt -3) < rx_length) {
// TODO: get data
}
if ((rx_bcnt -2) == rx_length) {
/* enable RS485 TX */
PORTD |= (1<<RXTX);
/* first byte */
tx_cmd = rx_cmd;
UDR = rx_cmd;
/* prepare header */
tx_bcnt = 1;
tx_cause = 0;
tx_length = 0;
if (tx_cmd == CMD_GET_VERSION) {
tx_length = sizeof(versioninfo);
}
/* enable interrupt */
UCSRB |= (1<<UDRIE);
}
rx_bcnt++;
} }
} }
#else
#define print_values(data)
#endif /* (BAUDRATE) */
ISR(USART_UDRE_vect)
{
/* enable IRQs again, but prevent multiple UDRE IRQs */
UCSRB &= ~(1<<UDRIE);
sei();
if ((tx_bcnt < 4) || (tx_bcnt -4) < tx_length) {
uint16_t pos = (tx_bcnt -4);
uint8_t data = 0xFF;
if (tx_bcnt == 1) {
data = tx_cause;
} else if (tx_bcnt == 2) {
data = (tx_length >> 8);
} else if (tx_bcnt == 3) {
data = (tx_length & 0xFF);
} else if (tx_cmd == CMD_GET_VERSION) {
data = versioninfo[pos];
} else {
data = 0xAA;
}
UDR = data;
/* re-enable for next round */
UCSRB |= (1<<UDRIE);
}
tx_bcnt++;
}
ISR(USART_TXC_vect, ISR_NOBLOCK)
{
/* disable RS485 TX */
PORTD &= ~(1<<RXTX);
/* enable MP mode again */
UCSRA |= (1<<MPCM);
rx_bcnt = 0xFF; // FIXME: cli?
if (tx_cmd == CMD_SWITCH_MODE) { // FIXME: check mode
wdt_enable(WDTO_15MS);
}
}
int main(void) __attribute__ ((noreturn));
int main(void) int main(void)
{ {
/* 16 PWM Outputs */ /* 16 PWM Outputs */
PORTA = 0x00; PORTA = 0x00;
DDRA = 0xFF; DDRA = 0xFF;
PORTB = 0x00;
DDRB = (1<<ROW1) | (1<<ROW2) | (1<<ROW3) | (1<<ROW4);
PORTC = 0x00; PORTC = 0x00;
DDRC = 0xFF; DDRC = 0xFF;
PORTD = (1<<RXTX) | (1<<LED); /* color ROWs */
PORTB = 0x00;
DDRB = (1<<ROW1) | (1<<ROW2) | (1<<ROW3) | (1<<ROW4);
PORTD = (1<<LED);
DDRD = (1<<RXTX) | (1<<LED); DDRD = (1<<RXTX) | (1<<LED);
#if (STANDALONE)
OSCCAL = OSCCAL_VALUE;
#endif /* (STANDALONE) */
/* timer0, FCPU/64, overflow interrupt */ /* timer0, FCPU/64, overflow interrupt */
TCCR0 = (1<<CS01) | (1<<CS00); /* FCPU/64 */ TCCR0 = (1<<CS01) | (1<<CS00); /* FCPU/64 */
TIMSK = (1<<TOIE0); TIMSK = (1<<TOIE0);
TCNT0 = 0x00; TCNT0 = 0x00;
#if (BAUDRATE) /* USART config */
/* Set baud rate */ /* Multi Drop Mode, 9n1 */
UCSRA = (1<<MPCM);
UCSRB = (1<<RXEN) | (1<<TXEN) | (1<<RXCIE) | (1<<TXCIE) | (1<<UCSZ2);
UCSRC = (1<<URSEL) | (1<<UCSZ1) | (1<<UCSZ0);
#if (STANDALONE)
UBRRH = (UART_CALC_BAUDRATE(BAUDRATE)>>8) & 0xFF; UBRRH = (UART_CALC_BAUDRATE(BAUDRATE)>>8) & 0xFF;
UBRRL = (UART_CALC_BAUDRATE(BAUDRATE) & 0xFF); UBRRL = (UART_CALC_BAUDRATE(BAUDRATE) & 0xFF);
/* enable usart with 8n1 */ /* MPM address stored in TWI address register */
UCSRB = (1<<TXEN) | (1<<RXEN); TWAR = MPM_ADDRESS;
UCSRC = (1<<URSEL) | (1<<UCSZ1) | (1<<UCSZ0); #endif /* (STANDALONE) */
fprintf(&uart, "good morning dave\n");
#endif /* (BAUDRATE) */
sei(); sei();
@ -368,29 +465,37 @@ int main(void)
uint16_t ramp = 0; uint16_t ramp = 0;
uint8_t step = 0; uint8_t step = 0;
#if 0
/* create worst case for R+G, relaxed for B */
for (x = 0; x < 16; x++) {
chan_value[0][x] = 254 - x;
chan_value[1][x] = x +1;
chan_value[2][x] = x * 16;
}
x = 0;
#endif
while (1) { while (1) {
uint8_t color_update = 0x07; uint8_t color_update = 0x07;
while (color_update) { while (color_update) {
if ((color_update & 0x01) && (nextColor == 2)) { if ((color_update & 0x01) && (nextColor == 2)) {
calculate_timer_values(chan_value[0], chan_rawdata[0]); calculate_timer_values(chan_value[0], chan_rawdata[0]);
color_update &= ~(0x01); color_update &= ~(0x01);
print_values(chan_rawdata[0]);
} else if ((color_update & 0x02) && (nextColor == 0)) { } else if ((color_update & 0x02) && (nextColor == 0)) {
calculate_timer_values(chan_value[1], chan_rawdata[1]); calculate_timer_values(chan_value[1], chan_rawdata[1]);
color_update &= ~(0x02); color_update &= ~(0x02);
print_values(chan_rawdata[1]);
} else if ((color_update & 0x04) && (nextColor == 1)) { } else if ((color_update & 0x04) && (nextColor == 1)) {
calculate_timer_values(chan_value[2], chan_rawdata[2]); calculate_timer_values(chan_value[2], chan_rawdata[2]);
color_update &= ~(0x04); color_update &= ~(0x04);
print_values(chan_rawdata[2]);
} }
} }
#if 1
PORTD ^= (1<<LED); PORTD ^= (1<<LED);
_delay_ms(100); // _delay_ms(100);
step++; step++;
if (step == 16) { if (step == 16) {
@ -473,7 +578,6 @@ int main(void)
#endif #endif
} }
} }
#endif
} }
return 0;
} }