-# $Id: Makefile,v 1.3 2010/06/27 22:19:15 simimeie Exp $
+# $Id: Makefile,v 1.4 2010/07/24 20:56:28 simimeie Exp $
# Makefile for HaWo Moodlight
CC = avr-gcc
# desired baudrate of serial debug console
BAUDRATE = 9600UL
-SRCS = console.c ledpwm.c ircontrol.c timers.c main.c
+SRCS = console.c ledframing.c ledpwm.c ircontrol.c timers.c main.c rfm12.c
PROG = moodlight
# compiler flags
-/* $Id: console.c,v 1.3 2010/06/30 19:40:49 simimeie Exp $
+/* $Id: console.c,v 1.4 2010/07/24 20:55:48 simimeie Exp $
* Functions for a serial console.
*/
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <avr/version.h>
+#include <avr/wdt.h>
#include <util/delay.h>
#include <stdio.h>
#include <stdlib.h>
#include "console.h"
#include "ledpwm.h"
+#include "rfm12.h"
/* PD0 is RXD, PD1 is TXD, but we don't need to address them manually */
"\r\nSoftware Version 0.1, Compiled " __DATE__ " " __TIME__;
static prog_uint8_t PROMPT[] = "\r\nroot@moodlight# ";
+uint8_t mcusr_mirror __attribute__ ((section (".noinit")));
+
+/* This is needed to recover from a watchdog reset, as the watchdog
+ * stays active after the reset.
+ * The variable is just to make the reason of the last reset accessible
+ * later. */
+void get_mcusr(void) __attribute__((naked)) __attribute__((section(".init3")));
+void get_mcusr(void) {
+ mcusr_mirror = MCUSR;
+ MCUSR = 0;
+ wdt_disable();
+}
+
/* Handler for TXC (TX Complete) IRQ */
ISR(USART_TX_vect) {
if (outputhead == outputtail) { /* Nothing more to send! */
/* Enable Send and Receive and IRQs */
UCSR0B = _BV(TXEN0) | _BV(RXEN0) | _BV(TXCIE0) | _BV(RXCIE0);
console_printpgm_noirq_P(WELCOMEMSG);
+ console_printpgm_noirq_P(PSTR("\r\nNOTE: last reset was from"));
+ if (mcusr_mirror & _BV(WDRF)) {
+ console_printpgm_noirq_P(PSTR(" WatchdogTimer"));
+ }
+ if (mcusr_mirror & _BV(BORF)) {
+ console_printpgm_noirq_P(PSTR(" Brownout"));
+ }
+ if (mcusr_mirror & _BV(EXTRF)) {
+ console_printpgm_noirq_P(PSTR(" ExternalReset"));
+ }
+ if (mcusr_mirror & _BV(PORF)) {
+ console_printpgm_noirq_P(PSTR(" PowerOn"));
+ }
console_printpgm_noirq_P(PROMPT);
return;
}
console_printpgm_noirq_P(PSTR("\r\n showpins [x] shows the avrs inputpins"));
console_printpgm_noirq_P(PSTR("\r\n status show status / counters"));
console_printpgm_noirq_P(PSTR("\r\n [rgb] n sets the brightness of the red / green / blue LED to n"));
+ console_printpgm_noirq_P(PSTR("\r\n rfstatus show RFM12 status"));
/* console_printpgm_noirq_P(PSTR("\r\n save saves settings to EEPROM")); */
} else if (strcmp_P(inputbuf, PSTR("motd")) == 0) {
console_printpgm_noirq_P(WELCOMEMSG);
console_printhex8_noirq(ledpwm_bl);
console_printpgm_noirq_P(PSTR(", brightness = "));
console_printhex8_noirq(ledpwm_bri);
- /*console_printpgm_noirq_P(CRLF);*/
} else if (strncmp_P(inputbuf, PSTR("r "), 2) == 0) {
uint8_t v;
v = strtoul(&inputbuf[2], NULL, 0);
ledpwm_re = v;
ledpwm_setled(LEDPWM_REDLED, (((uint16_t)ledpwm_re * ledpwm_bri) / 255));
- console_printpgm_P(PSTR("RED value set to 0x"));
- console_printhex8(v);
+ console_printpgm_noirq_P(PSTR("RED value set to 0x"));
+ console_printhex8_noirq(v);
} else if (strncmp_P(inputbuf, PSTR("g "), 2) == 0) {
uint8_t v;
v = strtoul(&inputbuf[2], NULL, 0);
ledpwm_gr = v;
ledpwm_setled(LEDPWM_GREENLED, (((uint16_t)ledpwm_gr * ledpwm_bri) / 255));
- console_printpgm_P(PSTR("GREEN value set to 0x"));
- console_printhex8(v);
+ console_printpgm_noirq_P(PSTR("GREEN value set to 0x"));
+ console_printhex8_noirq(v);
} else if (strncmp_P(inputbuf, PSTR("b "), 2) == 0) {
uint8_t v;
v = strtoul(&inputbuf[2], NULL, 0);
ledpwm_bl = v;
ledpwm_setled(LEDPWM_BLUELED, (((uint16_t)ledpwm_bl * ledpwm_bri) / 255));
- console_printpgm_P(PSTR("BLUE value set to 0x"));
- console_printhex8(v);
+ console_printpgm_noirq_P(PSTR("BLUE value set to 0x"));
+ console_printhex8_noirq(v);
} else if (strncmp_P(inputbuf, PSTR("bri "), 2) == 0) {
uint8_t v;
v = strtoul(&inputbuf[4], NULL, 0);
ledpwm_setled(LEDPWM_REDLED, (((uint16_t)ledpwm_re * ledpwm_bri) / 255));
ledpwm_setled(LEDPWM_GREENLED, (((uint16_t)ledpwm_gr * ledpwm_bri) / 255));
ledpwm_setled(LEDPWM_BLUELED, (((uint16_t)ledpwm_bl * ledpwm_bri) / 255));
- console_printpgm_P(PSTR("brightness set to 0x"));
- console_printhex8(v);
+ console_printpgm_noirq_P(PSTR("brightness set to 0x"));
+ console_printhex8_noirq(v);
+ } else if (strcmp_P(inputbuf, PSTR("rfstatus")) == 0) {
+ uint32_t st;
+ st = rfm12_readstatus();
+ console_printpgm_noirq_P(PSTR("rfm12 status is "));
+ console_printhex8_noirq(st >> 24);
+ console_printhex8_noirq(st >> 16);
+ console_printhex8_noirq(st >> 8);
+ console_printhex8_noirq(st >> 0);
#ifdef JOKECMDS
} else if (strncmp_P(inputbuf, PSTR("ls"), 2) == 0) {
console_printpgm_noirq_P(PSTR("Total 4711\r\n"));
--- /dev/null
+/* $Id: eepromdata.h,v 1.1 2010/07/24 20:55:48 simimeie Exp $
+ * Defines the contents of the EEPROM.
+ * The EEPROM contains settings and can also contain "programs" for the LEDs.
+ * Usually you only need to reprogram the eeprom after changing values here,
+ * unless compiler version changed and thus the data got reordered.
+ */
+
+#define EEPROM __attribute__ ((section (".eeprom")))
+
+/* The default brightness */
+uint8_t EEPROM ee_defledbrightness = 128;
+
+/* All the rest of the memory is used for storing LED "programs".
+ * For the following to work, <avr/io.h> needs to be included before this file -
+ * which usually should be the case anyways.
+ * Formula is: E2END + 1 - (number of bytes used by other stuff in EEPROM) */
+uint8_t EEPROM ee_ledprograms[E2END + 1 - 1];
+
-/* $Id: main.c,v 1.6 2010/07/10 07:32:08 simimeie Exp $
+/* $Id: main.c,v 1.7 2010/07/24 20:55:48 simimeie Exp $
* Main file for the HaWo moodlight.
* This is the main file that glues it all together. It also contains all
* functionality that is too small to require an extra file.
#include "ledpwm.h"
#include "ircontrol.h"
#include "timers.h"
-/* #include "eepromdata.h" */
-
-uint8_t mcusr_mirror __attribute__ ((section (".noinit")));
-
-/* This is needed to recover from a watchdog reset, as the watchdog
- * stays active after the reset.
- * The variable is just to make the reason of the last reset accessible
- * later. */
-void get_mcusr(void) __attribute__((naked)) __attribute__((section(".init3")));
-void get_mcusr(void) {
- mcusr_mirror = MCUSR;
- MCUSR = 0;
- wdt_disable();
-}
+#include "ledframing.h"
+#include "rfm12.h"
+#include "eepromdata.h"
#define IRSTATE_RED 1
#define IRSTATE_GREEN 2
uint8_t irstate = 0;
/* Load settings from EEPROM */
-#if 0
- something = eeprom_read_byte(&ee_something);
-#endif /* LEDMODULE */
+ ledpwm_bri = eeprom_read_byte(&ee_defledbrightness);
/* Initialize stuff */
console_init();
timers_init();
ledpwm_init();
+ ledframing_init();
ircontrol_init();
+ rfm12_init();
wdt_enable(WDTO_2S);
/* All set up, enable interrupts and go. */
sei();
- if (mcusr_mirror & _BV(WDRF)) {
- console_printpgm_P(PSTR("NOTE: last reset was from Watchdog Timer."));
- }
- if (mcusr_mirror & _BV(BORF)) {
- console_printpgm_P(PSTR("NOTE: last reset was from Brownout."));
- }
-
while (1) { /* We should never exit */
wdt_reset();
uint8_t k = ircontrol_getlastcommand();
-/* $Id: rfm12.c,v 1.1 2010/07/11 09:09:26 simimeie Exp $
+/* $Id: rfm12.c,v 1.2 2010/07/24 20:55:48 simimeie Exp $
* Functions for communicating with the rfm12(b) module
*/
/* Consequently, this SELECTS the chip */
#define spi_ss_lo() { PORTC &= (uint8_t)~_BV(0); }
-static void spi_sendbyte(uint8_t v) {
+/* write and (at the same time) read a word from RFM12.
+ * The module uses 16 bit commands and replies that are
+ * synchronous to the command - except for the status read.
+ * Note: This does not handle chip select! */
+static uint16_t rfm12_spi_wrword(uint16_t v) {
+ uint16_t res;
/* Start transmission */
- SPDR = v;
+ SPDR = v >> 8;
/* Wait for transmission complete */
while ((SPSR & _BV(SPIF)) == 0) {
}
-}
-
-static uint8_t spi_readbyte() {
- SPDR = 0x00; /* Dummy write */
+ res = (uint16_t)(SPDR) << 8;
+ SPDR = v & 0xff;
+ /* Wait for transmission complete */
while ((SPSR & _BV(SPIF)) == 0) {
}
- /* Return Data Register */
- return SPDR;
+ res |= SPDR & 0xff;
+ return res;
+}
+
+void rfm12_sendcommand(uint16_t cmd) {
+ spi_ss_lo();
+ rfm12_spi_wrword(cmd);
+ spi_ss_hi();
+}
+
+uint32_t rfm12_readstatus(void) {
+ uint32_t res;
+ spi_ss_lo();
+ res = (uint32_t)rfm12_spi_wrword(0x0000) << 16;
+ res |= rfm12_spi_wrword(0x0000);
+ spi_ss_hi();
+ return res;
}
void rfm12_init(void) {
/* Set MOSI, SCK and SS output, MISO input */
- DDRB |= _BV(3) | _BV(5);
+ /* Frickel Alert: Also set PB2 output. It is not used, but noise on the
+ * pin could reset our SPI mode to slave (!!!) if it is left as input. */
+ DDRB |= _BV(3) | _BV(5) | _BV(2);
DDRC |= _BV(0);
DDRB &= (uint8_t)~_BV(4);
spi_ss_hi();
+#if (CPUFREQ <= 10000000UL)
/* Enable SPI, Master, set clock rate fck/4.
* This works as long as our own clockrate is below 10 MHz - because
* 2.5 MHz is the maximum the rfm12b can do. */
SPCR |= _BV(SPE) | _BV(MSTR);
+#else
+ /* For higher clock rates set fck/16. */
+ SPCR |= _BV(SPE) | _BV(MSTR) | _BV(SPR0);
+#endif /* CPUFREQ */
+ /* Now send some initialization commands. */
+ /* Mostly taken over from http://www.joachim-neu.de/post/70/rfm12b-868/
+ * Seems to be mostly black magic anyways. */
+ rfm12_sendcommand(0x80E7); /* EL, EF, 868band, 12.0pF */
+ rfm12_sendcommand(0x8219); /* !er, !ebb, !ET, ES, EX, !eb, !ew, DC */
+ /* Frequency setting: 0xAnnn; the 12 nnn-bits of value are
+ * calculated like this: v = ((freq / 20) - 43) * 4000
+ */
+ rfm12_sendcommand(0xA7BC); /* 869,900 MHz */
+ rfm12_sendcommand(0xC647); /* 4.8kbps FIXME? */
+ rfm12_sendcommand(0x94C0); /* VDI, FAST, 67kHz, 0dBm, -103dBm */
+ rfm12_sendcommand(0xC2AC); /* AL, !ml, DIG, DQD4 */
+ rfm12_sendcommand(0xCA81);//FIFO8,SYNC,!ff,DR
+ rfm12_sendcommand(0xCED4);//SYNC=2DD4;
+ rfm12_sendcommand(0xC483);//@PWR,NO RSTRIC,!st,!fi,OE,EN
+ rfm12_sendcommand(0x9820);// !mp,45kHz,MAX OUT*/
+ rfm12_sendcommand(0xCC77);//OB1,OB0, LPX,!ddy,DDIT,BW0
+ rfm12_sendcommand(0xE000);//NOT USE
+ rfm12_sendcommand(0xC800);//NOT USE
+ rfm12_sendcommand(0xC040);//1.66MHz,2.2V
}
-/* $Id: rfm12.h,v 1.1 2010/07/11 09:09:26 simimeie Exp $
+/* $Id: rfm12.h,v 1.2 2010/07/24 20:55:48 simimeie Exp $
* Functions for communicating with the rfm12(b) module
*/
#define __RFM12B_H__
void rfm12_init(void);
+void rfm12_sendcommand(uint16_t cmd);
+uint32_t rfm12_readstatus(void);
#endif /* __RFM12B_H__ */