working 16ch RGB version
This commit is contained in:
commit
c9f2f64636
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
*.o
|
||||||
|
*.elf
|
||||||
|
*.bin
|
||||||
|
*.hex
|
||||||
|
*.lst
|
||||||
|
*.map
|
52
Makefile
Normal file
52
Makefile
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
PRG = 16ch_pwm
|
||||||
|
OBJ = main.o
|
||||||
|
MCU_TARGET = atmega16
|
||||||
|
OPTIMIZE = -O2
|
||||||
|
|
||||||
|
DEFS =
|
||||||
|
LIBS =
|
||||||
|
|
||||||
|
# You should not have to change anything below here.
|
||||||
|
|
||||||
|
CC = avr-gcc
|
||||||
|
|
||||||
|
# Override is only needed by avr-lib build system.
|
||||||
|
|
||||||
|
override CFLAGS = -g -Wall $(OPTIMIZE) -mmcu=$(MCU_TARGET) $(DEFS)
|
||||||
|
override LDFLAGS = -Wl,-Map,$(PRG).map
|
||||||
|
|
||||||
|
OBJCOPY = avr-objcopy
|
||||||
|
OBJDUMP = avr-objdump
|
||||||
|
SIZE = avr-size
|
||||||
|
|
||||||
|
all: $(PRG).elf lst text
|
||||||
|
$(SIZE) -x -A $(PRG).elf
|
||||||
|
|
||||||
|
$(PRG).elf: $(OBJ)
|
||||||
|
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf *.o *.lst *.map $(PRG).elf *.hex *.bin
|
||||||
|
|
||||||
|
lst: $(PRG).lst
|
||||||
|
|
||||||
|
%.lst: %.elf
|
||||||
|
$(OBJDUMP) -h -S $< > $@
|
||||||
|
|
||||||
|
# Rules for building the .text rom images
|
||||||
|
|
||||||
|
text: hex bin
|
||||||
|
|
||||||
|
hex: $(PRG).hex
|
||||||
|
bin: $(PRG).bin
|
||||||
|
|
||||||
|
%.hex: %.elf
|
||||||
|
$(OBJCOPY) -j .text -j .data -O ihex $< $@
|
||||||
|
|
||||||
|
%.bin: %.elf
|
||||||
|
$(OBJCOPY) -j .text -j .data -O binary $< $@
|
||||||
|
|
||||||
|
install: text
|
||||||
|
# uisp -dprog=stk200 --erase --upload if=$(PRG).hex --verify
|
||||||
|
# avrdude -p m16 -c butterfly -b 19200 -P /dev/ttyUSB0 -U flash:w:$(PRG).hex
|
||||||
|
avrdude -p m16 -c dragon_isp -P usb -U flash:w:$(PRG).hex
|
236
main.c
Normal file
236
main.c
Normal file
@ -0,0 +1,236 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* C based avr910 / avr109 ISP Adapter *
|
||||||
|
* *
|
||||||
|
* 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 <avr/io.h>
|
||||||
|
#include <avr/interrupt.h>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* using ATmega16 @7.3728MHz:
|
||||||
|
* Fuse H: 0xDA (512 words bootloader, jtag disabled)
|
||||||
|
* Fuse L: 0xFF (ext. Crystal)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define F_CPU 7372800
|
||||||
|
#include <util/delay.h>
|
||||||
|
|
||||||
|
#define BAUDRATE 9600
|
||||||
|
#define UART_CALC_BAUDRATE(baudRate) (((uint32_t)F_CPU) / (((uint32_t)baudRate)*16) -1)
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
static int uart_putchar(char c, FILE *stream)
|
||||||
|
{
|
||||||
|
if (c == '\n')
|
||||||
|
uart_putchar('\r', stream);
|
||||||
|
|
||||||
|
loop_until_bit_is_set(UCSRA, UDRE);
|
||||||
|
UDR = c;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static FILE uart = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_WRITE);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static uint8_t valueR[16] = {
|
||||||
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
|
// 0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E,
|
||||||
|
// 0x01, 0x03, 0x05, 0x07, 0x09, 0x0B, 0x0D, 0x0F,
|
||||||
|
};
|
||||||
|
|
||||||
|
static uint8_t valueG[16] = {
|
||||||
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
||||||
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
||||||
|
// 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, 0xA0, 0xB0,
|
||||||
|
// 0x48, 0x58, 0x68, 0x78, 0x88, 0x98, 0xA8, 0xB8,
|
||||||
|
};
|
||||||
|
|
||||||
|
static uint8_t valueB[16] = {
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
// 0xF1, 0xF3, 0xF5, 0xF7, 0xF9, 0xFB, 0xFD, 0xFF,
|
||||||
|
// 0xF0, 0xF2, 0xF4, 0xF6, 0xF8, 0xFA, 0xFC, 0xFE,
|
||||||
|
};
|
||||||
|
|
||||||
|
static uint8_t *current_comp_reg;
|
||||||
|
static uint8_t comp_regR[16];
|
||||||
|
static uint8_t comp_regG[16];
|
||||||
|
static uint8_t comp_regB[16];
|
||||||
|
|
||||||
|
static uint16_t *current_port_reg;
|
||||||
|
static uint16_t port_regR[16 +1];
|
||||||
|
static uint16_t port_regG[16 +1];
|
||||||
|
static uint16_t port_regB[16 +1];
|
||||||
|
|
||||||
|
static uint8_t current_color;
|
||||||
|
|
||||||
|
ISR(SIG_OVERFLOW0)
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
/* switch color */
|
||||||
|
switch (current_color) {
|
||||||
|
case 0: /* RED */
|
||||||
|
current_comp_reg = comp_regR;
|
||||||
|
current_port_reg = port_regR;
|
||||||
|
current_color = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1: /* GREEN */
|
||||||
|
current_comp_reg = comp_regG;
|
||||||
|
current_port_reg = port_regG;
|
||||||
|
current_color = 2;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2: /* BLUE */
|
||||||
|
current_comp_reg = comp_regB;
|
||||||
|
current_port_reg = port_regB;
|
||||||
|
current_color = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
current_comp_reg = comp_regR;
|
||||||
|
current_port_reg = port_regR;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uint16_t port_reg = *current_port_reg++;
|
||||||
|
PORTA = (port_reg & 0xFF);
|
||||||
|
PORTC = (port_reg >> 8) & 0xFF;
|
||||||
|
|
||||||
|
/* enable compare interrupts if any pin is active */
|
||||||
|
if (port_reg != 0x0000) {
|
||||||
|
TIMSK |= (1<<OCIE0);
|
||||||
|
}
|
||||||
|
|
||||||
|
OCR0 = *current_comp_reg++;
|
||||||
|
}
|
||||||
|
|
||||||
|
ISR(SIG_OUTPUT_COMPARE0)
|
||||||
|
{
|
||||||
|
uint16_t port_reg = *current_port_reg++;
|
||||||
|
PORTA = (port_reg & 0xFF);
|
||||||
|
PORTC = (port_reg >> 8) & 0xFF;
|
||||||
|
|
||||||
|
/* no further compare interrupts needed */
|
||||||
|
if (port_reg == 0x0000) {
|
||||||
|
TIMSK &= ~(1<<OCIE0);
|
||||||
|
}
|
||||||
|
|
||||||
|
OCR0 = *current_comp_reg++;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void calculate_timer_values(uint8_t *value, uint8_t *comp_reg, uint16_t *port_reg)
|
||||||
|
{
|
||||||
|
uint8_t index = 0;
|
||||||
|
uint16_t chan_used = 0xFFFF;
|
||||||
|
uint16_t chan_init = 0xFFFF;
|
||||||
|
|
||||||
|
/* loop until all channels are calculated */
|
||||||
|
while (chan_used) {
|
||||||
|
|
||||||
|
uint8_t i;
|
||||||
|
uint8_t min_value = 0xFF;
|
||||||
|
uint16_t chan_tmp = chan_used;
|
||||||
|
uint16_t chan_mask = 0x0001;
|
||||||
|
|
||||||
|
for (i = 0; i < 16; i++) {
|
||||||
|
|
||||||
|
/* skip if channel already used */
|
||||||
|
if (chan_used & chan_mask)
|
||||||
|
{
|
||||||
|
/* channel is not used (value 0x00) */
|
||||||
|
if (value[i] == 0x00) {
|
||||||
|
chan_init &= (~chan_mask);
|
||||||
|
chan_used &= (~chan_mask);
|
||||||
|
|
||||||
|
/* found a new lower value */
|
||||||
|
} else if (value[i] < min_value) {
|
||||||
|
min_value = value[i];
|
||||||
|
chan_tmp = chan_used & (~chan_mask);
|
||||||
|
|
||||||
|
/* found another value with the same value */
|
||||||
|
} else if (value[i] == min_value) {
|
||||||
|
chan_tmp &= (~chan_mask);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
chan_mask <<= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
chan_used &= chan_tmp;
|
||||||
|
|
||||||
|
// TODO: what if all channels are 0xFF, old value?
|
||||||
|
if (min_value < 0xFF) {
|
||||||
|
comp_reg[index] = min_value -1;
|
||||||
|
port_reg[index +1] = chan_used;
|
||||||
|
}
|
||||||
|
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (index < 16) {
|
||||||
|
comp_reg[index] = 0x00;
|
||||||
|
port_reg[index +1] = chan_used;
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
port_reg[0] = chan_init;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
/* 16 PWM Outputs */
|
||||||
|
PORTA = 0x00;
|
||||||
|
PORTC = 0x00;
|
||||||
|
DDRA = 0xFF;
|
||||||
|
DDRC = 0xFF;
|
||||||
|
|
||||||
|
/* timer0, FCPU/256, overflow interrupt */
|
||||||
|
TCCR0 = (1<<CS02);
|
||||||
|
TIMSK = (1<<TOIE0);
|
||||||
|
TCNT0 = 0x00;
|
||||||
|
|
||||||
|
/* Set baud rate */
|
||||||
|
UBRRH = (UART_CALC_BAUDRATE(BAUDRATE)>>8) & 0xFF;
|
||||||
|
UBRRL = (UART_CALC_BAUDRATE(BAUDRATE) & 0xFF);
|
||||||
|
|
||||||
|
/* enable usart with 8n1 */
|
||||||
|
UCSRB = (1<<TXEN) | (1<<RXEN);
|
||||||
|
UCSRC = (1<<URSEL) | (1<<UCSZ1) | (1<<UCSZ0);
|
||||||
|
|
||||||
|
// fprintf(&uart, "good morning dave\n");
|
||||||
|
|
||||||
|
PORTA = 0x01;
|
||||||
|
calculate_timer_values(valueR, comp_regR, port_regR);
|
||||||
|
|
||||||
|
PORTA = 0x02;
|
||||||
|
calculate_timer_values(valueG, comp_regG, port_regG);
|
||||||
|
|
||||||
|
PORTA = 0x04;
|
||||||
|
calculate_timer_values(valueB, comp_regB, port_regB);
|
||||||
|
|
||||||
|
PORTA = 0x00;
|
||||||
|
|
||||||
|
sei();
|
||||||
|
while (1);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user