Skip to content

Instantly share code, notes, and snippets.

@Miceuz
Last active August 29, 2015 14:03
Show Gist options
  • Save Miceuz/1a32355f077c8457fef7 to your computer and use it in GitHub Desktop.
Save Miceuz/1a32355f077c8457fef7 to your computer and use it in GitHub Desktop.
// ==============================================================================
// 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