]>
Commit | Line | Data |
---|---|---|
ff29bc2b | 1 | /* $Id: rfm12.c,v 1.2 2010/07/24 20:55:48 simimeie Exp $ |
c95cbd3f | 2 | * Functions for communicating with the rfm12(b) module |
3 | */ | |
4 | ||
5 | #include <avr/io.h> | |
6 | #include "rfm12.h" | |
7 | ||
8 | /* Unfortunately, the manufacturer documentation for chip and module is | |
9 | * almost unreadable crap. | |
10 | * This one is better: http://www.mikrocontroller.net/articles/RFM12 | |
11 | */ | |
12 | /* Note: the signal is inverted, thus pulling this high DEselects the chip */ | |
13 | #define spi_ss_hi() { PORTC |= _BV(0); } | |
14 | /* Consequently, this SELECTS the chip */ | |
15 | #define spi_ss_lo() { PORTC &= (uint8_t)~_BV(0); } | |
16 | ||
ff29bc2b | 17 | /* write and (at the same time) read a word from RFM12. |
18 | * The module uses 16 bit commands and replies that are | |
19 | * synchronous to the command - except for the status read. | |
20 | * Note: This does not handle chip select! */ | |
21 | static uint16_t rfm12_spi_wrword(uint16_t v) { | |
22 | uint16_t res; | |
c95cbd3f | 23 | /* Start transmission */ |
ff29bc2b | 24 | SPDR = v >> 8; |
c95cbd3f | 25 | /* Wait for transmission complete */ |
26 | while ((SPSR & _BV(SPIF)) == 0) { | |
27 | } | |
ff29bc2b | 28 | res = (uint16_t)(SPDR) << 8; |
29 | SPDR = v & 0xff; | |
30 | /* Wait for transmission complete */ | |
c95cbd3f | 31 | while ((SPSR & _BV(SPIF)) == 0) { |
32 | } | |
ff29bc2b | 33 | res |= SPDR & 0xff; |
34 | return res; | |
35 | } | |
36 | ||
37 | void rfm12_sendcommand(uint16_t cmd) { | |
38 | spi_ss_lo(); | |
39 | rfm12_spi_wrword(cmd); | |
40 | spi_ss_hi(); | |
41 | } | |
42 | ||
43 | uint32_t rfm12_readstatus(void) { | |
44 | uint32_t res; | |
45 | spi_ss_lo(); | |
46 | res = (uint32_t)rfm12_spi_wrword(0x0000) << 16; | |
47 | res |= rfm12_spi_wrword(0x0000); | |
48 | spi_ss_hi(); | |
49 | return res; | |
c95cbd3f | 50 | } |
51 | ||
52 | void rfm12_init(void) { | |
53 | /* Set MOSI, SCK and SS output, MISO input */ | |
ff29bc2b | 54 | /* Frickel Alert: Also set PB2 output. It is not used, but noise on the |
55 | * pin could reset our SPI mode to slave (!!!) if it is left as input. */ | |
56 | DDRB |= _BV(3) | _BV(5) | _BV(2); | |
c95cbd3f | 57 | DDRC |= _BV(0); |
58 | DDRB &= (uint8_t)~_BV(4); | |
59 | spi_ss_hi(); | |
ff29bc2b | 60 | #if (CPUFREQ <= 10000000UL) |
c95cbd3f | 61 | /* Enable SPI, Master, set clock rate fck/4. |
62 | * This works as long as our own clockrate is below 10 MHz - because | |
63 | * 2.5 MHz is the maximum the rfm12b can do. */ | |
64 | SPCR |= _BV(SPE) | _BV(MSTR); | |
ff29bc2b | 65 | #else |
66 | /* For higher clock rates set fck/16. */ | |
67 | SPCR |= _BV(SPE) | _BV(MSTR) | _BV(SPR0); | |
68 | #endif /* CPUFREQ */ | |
69 | /* Now send some initialization commands. */ | |
70 | /* Mostly taken over from http://www.joachim-neu.de/post/70/rfm12b-868/ | |
71 | * Seems to be mostly black magic anyways. */ | |
72 | rfm12_sendcommand(0x80E7); /* EL, EF, 868band, 12.0pF */ | |
73 | rfm12_sendcommand(0x8219); /* !er, !ebb, !ET, ES, EX, !eb, !ew, DC */ | |
74 | /* Frequency setting: 0xAnnn; the 12 nnn-bits of value are | |
75 | * calculated like this: v = ((freq / 20) - 43) * 4000 | |
76 | */ | |
77 | rfm12_sendcommand(0xA7BC); /* 869,900 MHz */ | |
78 | rfm12_sendcommand(0xC647); /* 4.8kbps FIXME? */ | |
79 | rfm12_sendcommand(0x94C0); /* VDI, FAST, 67kHz, 0dBm, -103dBm */ | |
80 | rfm12_sendcommand(0xC2AC); /* AL, !ml, DIG, DQD4 */ | |
81 | rfm12_sendcommand(0xCA81);//FIFO8,SYNC,!ff,DR | |
82 | rfm12_sendcommand(0xCED4);//SYNC=2DD4; | |
83 | rfm12_sendcommand(0xC483);//@PWR,NO RSTRIC,!st,!fi,OE,EN | |
84 | rfm12_sendcommand(0x9820);// !mp,45kHz,MAX OUT*/ | |
85 | rfm12_sendcommand(0xCC77);//OB1,OB0, LPX,!ddy,DDIT,BW0 | |
86 | rfm12_sendcommand(0xE000);//NOT USE | |
87 | rfm12_sendcommand(0xC800);//NOT USE | |
88 | rfm12_sendcommand(0xC040);//1.66MHz,2.2V | |
c95cbd3f | 89 | } |