Last active
August 29, 2015 14:03
-
-
Save Miceuz/1a32355f077c8457fef7 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ============================================================================== | |
// uDMX.c | |
// firmware for usb to dmx interface | |
// | |
// License: | |
// The project is built with AVR USB driver by Objective Development, which is | |
// published under an own licence based on the GNU General Public License (GPL). | |
// usb2dmx is also distributed under this enhanced licence. See Documentation. | |
// | |
// target-cpu: ATMega8 @ 12MHz | |
// created 2006-02-09 mexx | |
// | |
// version 1.4 2009-06-09 [email protected] | |
// - changed usb init routine | |
// version 1.3: 2008-11-04 [email protected] | |
// ============================================================================== | |
#define F_CPU 16000000 // 16MHz processor | |
// ============================================================================== | |
// includes | |
// ------------------------------------------------------------------------------ | |
// AVR Libc (see http://www.nongnu.org/avr-libc/) | |
#include <avr/io.h> // include I/O definitions (port names, pin names, etc) | |
#include <avr/pgmspace.h> // include program space (for PROGMEM) | |
#include <avr/interrupt.h> // include interrupt support | |
#include <avr/wdt.h> // include watchdog timer support | |
#include <avr/sleep.h> // include cpu sleep support | |
#include <util/delay.h> | |
#include "logvalues.h" | |
#include "udmx.h" | |
typedef unsigned char u08; | |
typedef signed char s08; | |
typedef unsigned short u16; | |
typedef signed short s16; | |
// ============================================================================== | |
// Globals | |
// ------------------------------------------------------------------------------ | |
// dmx-related globals | |
static u08 dmx_data[NUM_CHANNELS]; | |
static u16 out_idx; // index of next frame to send | |
static u16 packet_len = 3; // we only send frames up to the highest channel set | |
static u08 dmx_state; | |
//led keep alive counter | |
static u16 lka_count; | |
// ============================================================================== | |
// - sleepIfIdle | |
// ------------------------------------------------------------------------------ | |
void sleepIfIdle() | |
{ | |
if(TIFR & BV(TOV1)) { | |
cli(); | |
if(!(GIFR & BV(INTF1))) { | |
// no activity on INT1 pin for >3ms => suspend: | |
// turn off leds | |
// - reconfigure INT1 to level-triggered and enable for wake-up | |
cbi(MCUCR, ISC10); | |
sbi(GICR, INT1); | |
// - go to sleep | |
wdt_disable(); | |
sleep_enable(); | |
sei(); | |
sleep_cpu(); | |
// wake up | |
sleep_disable(); | |
// - reconfigure INT1 to any edge for SE0-detection | |
cbi(GICR, INT1); | |
sbi(MCUCR, ISC10); | |
// - re-enable watchdog | |
wdt_reset(); | |
wdt_enable(WDTO_1S); | |
} | |
sei(); | |
// clear INT1 flag | |
sbi(GIFR, INTF1); | |
// reload timer and clear overflow | |
TCCR1B = 1; | |
TCNT1 = 25000; // max ca. 3ms between SE0 | |
sbi(TIFR, TOV1); | |
} | |
} | |
// ------------------------------------------------------------------------------ | |
// - INT1_vec (dummy for wake-up) | |
// ------------------------------------------------------------------------------ | |
ISR(INT1_vect) {} | |
// ------------------------------------------------------------------------------ | |
// - Write to EEPROM | |
// ------------------------------------------------------------------------------ | |
static void eepromWrite(unsigned char addr, unsigned char val) | |
{ | |
while(EECR & (1 << EEWE)); | |
EEARL = addr; | |
EEDR = val; | |
cli(); | |
EECR |= 1 << EEMWE; | |
EECR |= 1 << EEWE; /* must follow within a couple of cycles -- therefore cli() */ | |
sei(); | |
} | |
// ============================================================================== | |
// - init | |
// ------------------------------------------------------------------------------ | |
void init(void) | |
{ | |
dmx_state = dmx_NewPacket; | |
lka_count = 0xffff; | |
//clear Power On reset flag | |
MCUCSR &= ~(1 << PORF); | |
// configure IO-Ports; most are unused, we set them to outputs to have defined voltages | |
//DDRB = 0xFF; /* set all pins as outputs except USB */ | |
//DDRC = 0xFF; // unused except PC0 and PC 4 for LEDS (outputs anyway...) | |
DDRD |= _BV(PD0) | _BV(PD1); // unused except PD2 + 3 (INT0 + 1), PD1 (TX) | |
PORTD |= _BV(PD0); | |
// and PD5 for Hardware Bootloader-Reset (pull to ground to force Bootloader) | |
// INT0 is used by USB driver, INT1 for bus activity detection (sleep) | |
// init uart | |
UBRRL = F_CPU/4000000 - 1; UBRRH = 0; // baud rate 250kbps | |
UCSRA = 0; // clear error flags | |
UCSRC = BV(URSEL) | BV(USBS) | (3 << UCSZ0); // 8 data bits, 2 stop bits, no parity (8N2) | |
UCSRB = 0; // don't turn on UART jet... | |
// init timer0 for DMX timing | |
TCCR0 = 2; // prescaler 8 => 1 clock is 2/3 us | |
// init Timer 1 and Interrupt 1 for usb activity detection: | |
// - set INT1 to any edge (polled by sleepIfIdle()) | |
// cbi(MCUCR, ISC11); | |
// sbi(MCUCR, ISC10); | |
//wdt_enable(WDTO_1S); // enable watchdog timer | |
// set sleep mode to full power-down for minimal consumption | |
//set_sleep_mode(SLEEP_MODE_PWR_DOWN); | |
// - set Timer 1 prescaler to 64 and restart timer | |
TCCR1B = 3; | |
TCNT1 = 0; | |
sbi(TIFR, TOV1); | |
sei(); | |
} | |
unsigned char readAdc(unsigned char channel) { | |
ADMUX = _BV(REFS0) | _BV(ADLAR) | channel; | |
ADCSRA |= _BV(ADSC); //start conversion | |
while(_BV(ADSC) & ADCSRA); //wait for possibly ongoing conversion to complete | |
return ADCH; | |
} | |
inline void adcInit() { | |
set_sleep_mode(SLEEP_MODE_ADC); | |
ADCSRA |= _BV(ADEN) | _BV(ADPS0) | _BV(ADPS1) | _BV(ADPS2); //enable ADC on slowest clock | |
} | |
// ============================================================================== | |
// - main | |
// ------------------------------------------------------------------------------ | |
int main(void) | |
{ | |
init(); | |
adcInit(); | |
while(1) { | |
// usb-related stuff | |
//wdt_reset(); | |
// keep flashing yellow led? | |
if (lka_count < 0xfff ) { | |
lka_count++; | |
PORTD |= _BV(LED_RED); | |
} else { | |
lka_count++; | |
PORTD &= ~_BV(LED_RED); | |
} | |
// do dmx transmission | |
switch(dmx_state) { | |
case dmx_NewPacket: { | |
// start a new dmx packet: | |
sbi(UCSRB, TXEN); // enable UART transmitter | |
out_idx = 0; // reset output channel index | |
sbi(UCSRA, TXC); // reset Transmit Complete flag | |
UDR = 0; // send start byte | |
dmx_state = dmx_InPacket; | |
break; | |
} | |
case dmx_InPacket: { | |
if(UCSRA & BV(UDRE)) { | |
// send next byte of dmx packet | |
if(out_idx < packet_len) { | |
UDR = dmx_data[out_idx++]; | |
break; | |
} else { | |
dmx_state = dmx_EndOfPacket; | |
} | |
} | |
else break; | |
} | |
case dmx_EndOfPacket: { | |
if(UCSRA & BV(TXC)) { | |
// send a BREAK: | |
cbi(UCSRB, TXEN); // disable UART transmitter | |
cbi(PORTD, 1); // pull TX pin low | |
sbi(SFIOR, PSR10); // reset timer prescaler | |
TCNT0 = 15; // 240 clks = 120us | |
sbi(TIFR, TOV0); // clear timer overflow flag | |
dmx_state = dmx_InBreak; | |
} | |
break; | |
} | |
case dmx_InBreak: { | |
if(TIFR & BV(TOV0)) { | |
//sleepIfIdle(); // if there's been no activity on USB for > 3ms, put CPU to sleep | |
// end of BREAK: send MARK AFTER BREAK | |
sbi(PORTD, 1); // pull TX pin high | |
sbi(SFIOR, PSR10); // reset timer prescaler | |
TCNT0 = 231; // 24 clks = 12us | |
sbi(TIFR, TOV0); // clear timer overflow flag | |
dmx_state = dmx_InMAB; | |
} | |
break; | |
} | |
case dmx_InMAB: { | |
if(TIFR & BV(TOV0)) { | |
// end of MARK AFTER BREAK; start new dmx packet | |
dmx_data[0]=pgm_read_byte(&logValues[255-readAdc(0)]); | |
dmx_data[1]=pgm_read_byte(&logValues[255-readAdc(1)]); | |
dmx_data[2]=pgm_read_byte(&logValues[255-readAdc(2)]); | |
dmx_state = dmx_NewPacket; | |
} | |
break; | |
} | |
} | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment