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 | } |