summaryrefslogtreecommitdiffstats
path: root/rf69
diff options
context:
space:
mode:
Diffstat (limited to 'rf69')
-rw-r--r--rf69/Recv.Makefile43
-rw-r--r--rf69/Send.Makefile44
-rw-r--r--rf69/radio.c212
-rw-r--r--rf69/radio.h22
-rw-r--r--rf69/recv.c64
-rw-r--r--rf69/send.c34
-rw-r--r--rf69/serial.c33
-rw-r--r--rf69/serial.h8
8 files changed, 460 insertions, 0 deletions
diff --git a/rf69/Recv.Makefile b/rf69/Recv.Makefile
new file mode 100644
index 0000000..67ac41f
--- /dev/null
+++ b/rf69/Recv.Makefile
@@ -0,0 +1,43 @@
+CC = avr-gcc
+MCU = atmega328p
+TARGET = recv
+
+SRC = radio.c recv.c serial.c
+OBJ = $(SRC:.c=.o)
+
+CFLAGS = -std=gnu99
+CFLAGS += -Os
+CFLAGS += -Wall
+CFLAGS += -mmcu=$(MCU)
+CFLAGS += -DBAUD=115200
+CFLAGS += -DF_CPU=16000000UL
+CFLAGS += -ffunction-sections -fdata-sections
+
+LDFLAGS = -mmcu=$(MCU)
+LDFLAGS += -Wl,--gc-sections
+
+HEX_FLAGS = -O ihex
+HEX_FLAGS += -j .text -j .data
+
+AVRDUDE_FLAGS = -p $(MCU)
+AVRDUDE_FLAGS += -c arduino
+AVRDUDE_FLAGS += -P /dev/cuaU0
+AVRDUDE_FLAGS += -D -U
+
+%.o: %.c
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+elf: $(OBJ)
+ $(CC) $(LDFLAGS) $(OBJ) -o $(TARGET).elf
+
+hex: elf
+ avr-objcopy $(HEX_FLAGS) $(TARGET).elf $(TARGET).hex
+
+upload: hex
+ avrdude $(AVRDUDE_FLAGS) flash:w:$(TARGET).hex:i
+
+.PHONY: clean
+
+clean:
+ rm *.o *.elf *.hex
+
diff --git a/rf69/Send.Makefile b/rf69/Send.Makefile
new file mode 100644
index 0000000..06e083b
--- /dev/null
+++ b/rf69/Send.Makefile
@@ -0,0 +1,44 @@
+CC = avr-gcc
+MCU = atmega328p
+TARGET = send
+
+SRC = radio.c send.c serial.c
+OBJ = $(SRC:.c=.o)
+
+CFLAGS = -std=gnu99
+CFLAGS += -Os
+CFLAGS += -Wall
+CFLAGS += -mmcu=$(MCU)
+CFLAGS += -DBAUD=115200
+CFLAGS += -DF_CPU=16000000UL
+CFLAGS += -ffunction-sections -fdata-sections
+
+LDFLAGS = -mmcu=$(MCU)
+LDFLAGS += -Wl,--gc-sections
+
+HEX_FLAGS = -O ihex
+HEX_FLAGS += -j .text -j .data
+
+AVRDUDE_FLAGS = -p $(MCU)
+AVRDUDE_FLAGS += -c arduino
+AVRDUDE_FLAGS += -P /dev/cuaU0
+AVRDUDE_FLAGS += -D -U
+
+%.o: %.c
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+elf: $(OBJ)
+ $(CC) $(LDFLAGS) $(OBJ) -o $(TARGET).elf
+
+hex: elf
+ avr-objcopy $(HEX_FLAGS) $(TARGET).elf $(TARGET).hex
+
+upload: hex
+ avrdude $(AVRDUDE_FLAGS) flash:w:$(TARGET).hex:i
+
+.PHONY: clean
+
+clean:
+ rm *.o *.elf *.hex
+
+
diff --git a/rf69/radio.c b/rf69/radio.c
new file mode 100644
index 0000000..f5d98c8
--- /dev/null
+++ b/rf69/radio.c
@@ -0,0 +1,212 @@
+#include <stdlib.h>
+
+#include <avr/io.h>
+#include <util/delay.h>
+
+#include "radio.h"
+#include "serial.h"
+
+#define SPI_SS PB2
+#define SPI_SCK PB5
+#define SPI_MISO PB4
+#define SPI_MOSI PB3
+#define SPI_DDR DDRB
+#define SPI_PORT PORTB
+
+#define RF69_OPMODE_RX 0x10
+#define RF69_OPMODE_TX 0x0C
+#define RF69_OPMODE_STDBY 0x04
+
+#define RF69_REG_FIFO 0x01
+#define RF69_REG_OPMODE 0x01
+#define RF69_REG_PALEVEL 0x11
+#define RF69_REG_TESTPA1 0x5A
+#define RF69_REG_TESTPA2 0x5C
+#define RF69_REG_IRQFLAGS1 0x27
+#define RF69_REG_IRQFLAGS2 0x28
+#define RF69_REG_DIOMAPPING1 0x25
+
+#define RF69_PALEVEL_PA1 0x40
+#define RF69_PALEVEL_PA2 0x20
+#define RF69_TESTPA1_BOOST 0x5D
+#define RF69_TESTPA2_BOOST 0x7C
+#define RF69_TESTPA1_NORMAL 0x55
+#define RF69_TESTPA2_NORMAL 0x70
+#define RF69_DIOMAPPING1_PACKET_SENT 0x00
+#define RF69_DIOMAPPING1_PAYLOAD_READY 0x40
+
+static int8_t power = 0;
+static uint8_t opmode = 0;
+
+static inline uint8_t read_reg(uint8_t reg)
+{
+ SPI_PORT &= ~(1 << SPI_SS);
+ SPDR = reg & 0x7F;
+ while (!(SPSR & (1 << SPIF)))
+ ;
+ SPDR = 0;
+ while (!(SPSR & (1 << SPIF)))
+ ;
+ SPI_PORT |= (1 << SPI_SS);
+ return SPDR;
+}
+
+static inline void write_reg(uint8_t reg, uint8_t val)
+{
+ SPI_PORT &= ~(1 << SPI_SS);
+ SPDR = reg | 0x80;
+ while (!(SPSR & (1 << SPIF)))
+ ;
+ SPDR = val;
+ while (!(SPSR & (1 << SPIF)))
+ ;
+ SPI_PORT |= (1 << SPI_SS);
+}
+
+static inline void set_mode(uint8_t mode)
+{
+ uint8_t val;
+
+ if (opmode != mode) {
+ if (mode == RF69_OPMODE_TX) {
+ if (power >= 18) {
+ write_reg(RF69_REG_TESTPA1, RF69_TESTPA1_BOOST);
+ write_reg(RF69_REG_TESTPA2, RF69_TESTPA2_BOOST);
+ }
+ write_reg(RF69_REG_DIOMAPPING1, RF69_DIOMAPPING1_PACKET_SENT);
+ } else {
+ if (power >= 18) {
+ write_reg(RF69_REG_TESTPA1, RF69_TESTPA1_NORMAL);
+ write_reg(RF69_REG_TESTPA2, RF69_TESTPA2_NORMAL);
+ }
+ if (mode == RF69_OPMODE_RX)
+ write_reg(RF69_REG_DIOMAPPING1, RF69_DIOMAPPING1_PAYLOAD_READY);
+ }
+
+ val = read_reg(RF69_REG_OPMODE);
+ val &= ~0x1C;
+ val |= (mode & 0x1C);
+
+ write_reg(RF69_REG_OPMODE, val);
+ while (!(read_reg(RF69_REG_IRQFLAGS1) & 0x80))
+ ;
+
+ opmode = mode;
+ }
+}
+
+void radio_set_tx_power(int8_t val)
+{
+ uint8_t pa;
+
+ power = val;
+
+ if (power < -2)
+ power = -2;
+
+ if (power <= 13)
+ pa = (RF69_PALEVEL_PA1 | ((power + 18) & 0x1F));
+ else if (power >= 18)
+ pa = (RF69_PALEVEL_PA1 | RF69_PALEVEL_PA2 | ((power + 11) & 0x1F));
+ else
+ pa = (RF69_PALEVEL_PA1 | RF69_PALEVEL_PA2 | ((power + 14) & 0x1F));
+
+ write_reg(RF69_REG_PALEVEL, pa);
+}
+
+void radio_send(const char *data, uint8_t n)
+{
+ uint8_t i, mode;
+
+ mode = opmode;
+ set_mode(RF69_OPMODE_STDBY);
+
+ SPI_PORT &= ~(1 << SPI_SS);
+
+ SPDR = RF69_REG_FIFO | 0x80;
+ while (!(SPSR & (1 << SPIF)))
+ ;
+
+ for (i = 0; i < n; i++) {
+ SPDR = data[i];
+ while (!(SPSR & (1 << SPIF)))
+ ;
+ }
+
+ SPI_PORT |= (1 << SPI_SS);
+
+ set_mode(RF69_OPMODE_TX);
+ while (!(read_reg(RF69_REG_IRQFLAGS2) & 0x08))
+ ;
+
+ set_mode(mode);
+}
+
+uint8_t radio_recv(char *buf, uint8_t n)
+{
+ uint8_t read_len, mode;
+
+ read_len = 0;
+ mode = opmode;
+
+ set_mode(RF69_OPMODE_STDBY);
+
+ SPI_PORT &= ~(1 << SPI_SS);
+
+ SPDR = RF69_REG_FIFO | 0x7F;
+ while (!(SPSR & (1 << SPIF)))
+ ;
+
+ while (read_len < n) {
+ SPDR = 0;
+ while (!(SPSR & (1 << SPIF)))
+ ;
+ buf[read_len++] = SPDR;
+ }
+
+ SPI_PORT |= (1 << SPI_SS);
+
+ set_mode(mode);
+ return read_len;
+}
+
+void radio_listen(void)
+{
+ set_mode(RF69_OPMODE_RX);
+}
+
+void radio_init(const struct radio_cfg *cfg)
+{
+ SPI_DDR |= (1 << SPI_SS) | (1 << SPI_SCK) | (1 << SPI_MOSI);
+ SPI_PORT |= (1 << SPI_SS);
+ SPCR |= (1 << SPE) | (1 << MSTR);
+
+ set_mode(RF69_OPMODE_STDBY);
+
+ // LNA, AFC and RXBW settings
+ write_reg(0x18, 0x88);
+ write_reg(0x19, 0x55);
+ write_reg(0x1A, 0x8B);
+
+ // DIO mappings: IRQ on DIO0
+ write_reg(0x25, 0x40);
+ write_reg(0x26, 0x07);
+
+ // RSSI threshold
+ write_reg(0x29, 0xE4);
+
+ // sync config
+ write_reg(0x2E, 0x80);
+ write_reg(0x2F, cfg->netid);
+
+ // packet config
+ write_reg(0x37, 0x10);
+ write_reg(0x38, cfg->payload_len);
+ write_reg(0x39, cfg->nodeid);
+
+ // fifo config
+ write_reg(0x3C, 0x8F);
+
+ // DAGC config
+ write_reg(0x6F, 0x30);
+}
diff --git a/rf69/radio.h b/rf69/radio.h
new file mode 100644
index 0000000..924da2d
--- /dev/null
+++ b/rf69/radio.h
@@ -0,0 +1,22 @@
+#ifndef RADIO_H
+#define RADIO_H
+
+#include <stdint.h>
+
+struct radio_cfg {
+ uint8_t netid;
+ uint8_t nodeid;
+ uint8_t payload_len;
+};
+
+void radio_init(const struct radio_cfg *cfg);
+
+void radio_set_tx_power(int8_t val);
+
+void radio_listen(void);
+
+void radio_send(const char *data, uint8_t n);
+
+uint8_t radio_recv(char *buf, uint8_t n);
+
+#endif
diff --git a/rf69/recv.c b/rf69/recv.c
new file mode 100644
index 0000000..1c6ac0f
--- /dev/null
+++ b/rf69/recv.c
@@ -0,0 +1,64 @@
+#include <avr/io.h>
+#include <avr/interrupt.h>
+
+#include "radio.h"
+#include "serial.h"
+
+#define RX_PIN PD7
+#define RX_DDR DDRD
+#define RX_PORT PORTD
+#define RX_PCIE PCIE2
+#define RX_PCINT PCINT23
+#define RX_PCMSK PCMSK2
+#define RX_PCINTVEC PCINT2_vect
+
+#define MAX_PAYLOAD_LEN 60
+
+static char *s = "hello, world!";
+static uint8_t slen = 13;
+
+int main(void)
+{
+ struct radio_cfg cfg;
+
+ cfg.netid = 0x01;
+ cfg.nodeid = 0x01;
+ cfg.payload_len = slen;
+
+ RX_DDR &= ~(1 << RX_PIN);
+ RX_PORT &= ~(1 << RX_PIN);
+ PCICR |= (1 << RX_PCIE);
+ RX_PCMSK |= (1 << RX_PCINT);
+
+ serial_init();
+
+ radio_init(&cfg);
+ radio_listen();
+
+ sei();
+
+ for (;;)
+ ;
+
+ return 0;
+}
+
+ISR(RX_PCINTVEC)
+{
+ uint8_t i, n;
+ char buf[MAX_PAYLOAD_LEN];
+
+ cli();
+
+ serial_write_line("Detected pin change IRQ");
+
+ n = radio_recv(buf, MAX_PAYLOAD_LEN - 1);
+ buf[n] = '\0';
+
+ for (i = 0; i < n; i++)
+ serial_write(buf[i]);
+ serial_write('\r');
+ serial_write('\n');
+
+ sei();
+}
diff --git a/rf69/send.c b/rf69/send.c
new file mode 100644
index 0000000..b390cf3
--- /dev/null
+++ b/rf69/send.c
@@ -0,0 +1,34 @@
+#include <stdlib.h>
+#include <string.h>
+
+#include <avr/io.h>
+#include <avr/interrupt.h>
+#include <util/delay.h>
+
+#include "radio.h"
+#include "serial.h"
+
+int main(void)
+{
+ uint8_t n;
+ struct radio_cfg cfg;
+ const char *s = "hello, world!";
+
+ n = strlen(s);
+
+ cfg.netid = 0x01;
+ cfg.nodeid = 0x02;
+ cfg.payload_len = n;
+
+ serial_init();
+ radio_init(&cfg);
+ radio_set_tx_power(18);
+
+ for (;;) {
+ radio_send(s, n);
+ serial_write_line("sent");
+ _delay_ms(1500);
+ }
+
+ return 0;
+}
diff --git a/rf69/serial.c b/rf69/serial.c
new file mode 100644
index 0000000..782e848
--- /dev/null
+++ b/rf69/serial.c
@@ -0,0 +1,33 @@
+#include <avr/io.h>
+#include <util/setbaud.h>
+
+#include "serial.h"
+
+void serial_init(void)
+{
+ UBRR0H = UBRRH_VALUE;
+ UBRR0L = UBRRL_VALUE;
+#if USE_2X
+ UCSR0A |= (1 << U2X0);
+#else
+ UCSR0A &= ~(1 << U2X0);
+#endif
+ UCSR0B = (1 << TXEN0) | (1 << RXEN0);
+ UCSR0C = (1 << UCSZ01) | (1 << UCSZ00);
+}
+
+void serial_write(char data)
+{
+ while (!(UCSR0A & (1 << UDRE0)))
+ ;
+ UDR0 = data;
+}
+
+void serial_write_line(const char *s)
+{
+ for (; *s; s++)
+ serial_write(*s);
+
+ serial_write('\r');
+ serial_write('\n');
+}
diff --git a/rf69/serial.h b/rf69/serial.h
new file mode 100644
index 0000000..0f9415b
--- /dev/null
+++ b/rf69/serial.h
@@ -0,0 +1,8 @@
+#ifndef SA_SERIAL_H
+#define SA_SERIAL_H
+
+void serial_init(void);
+void serial_write(char data);
+void serial_write_line(const char *s);
+
+#endif /* SA_SERIAL_H */