Stuff
This commit is contained in:
parent
445ae63ed6
commit
744db56269
|
@ -0,0 +1,58 @@
|
||||||
|
#include "driver.h"
|
||||||
|
#include <avr/interrupt.h>
|
||||||
|
#include <util/delay.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace driver
|
||||||
|
{
|
||||||
|
namespace {
|
||||||
|
Mrf24j *mrf;
|
||||||
|
}
|
||||||
|
void init(Mrf24j *mrf) {
|
||||||
|
driver::mrf = mrf;
|
||||||
|
SPI_PORT |= (1<<SPI_CS); //set chip select pin high
|
||||||
|
SPI_DDR |= (1<<SPI_SCK)|(1<<SPI_MOSI)|(1<<SPI_CS); // spi sck mosi and chip select outputs
|
||||||
|
RESET_PORT |= (1<<RESET);
|
||||||
|
RESET_DDR |= (1<<RESET);
|
||||||
|
SPCR |= (1<<SPE)|(1<<MSTR)|(1<<SPR0); //enable SPI , Master, fck/16
|
||||||
|
#ifdef WAKE_PORT
|
||||||
|
WAKE_PORT &= ~(1<<WAKE_PIN);
|
||||||
|
WAKE_DDR |= (1<<WAKE_PIN);
|
||||||
|
#endif
|
||||||
|
#if defined __AVR_ATmega328P__
|
||||||
|
EICRA |= (1<<ISC01);
|
||||||
|
EIMSK |= (1<<INT0);
|
||||||
|
SPSR |= (1<< SPI2X); // FOSC/2
|
||||||
|
#elif defined __AVR_ATmega32__
|
||||||
|
GICR |= (1<<INT2);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
sei();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t transfer(uint8_t data) {
|
||||||
|
SPDR = data;
|
||||||
|
while(!(SPSR & (1<<SPIF))); //wait for transmition to complete
|
||||||
|
return SPDR;
|
||||||
|
}
|
||||||
|
void reset() {
|
||||||
|
RESET_PORT &= ~(1<<RESET);
|
||||||
|
_delay_ms(10);
|
||||||
|
RESET_PORT |= (1<<RESET);
|
||||||
|
_delay_ms(20);
|
||||||
|
}
|
||||||
|
|
||||||
|
void wake() {
|
||||||
|
#ifdef WAKE_PORT
|
||||||
|
WAKE_PORT |= (1<<WAKE_PIN);
|
||||||
|
_delay_ms(1);
|
||||||
|
WAKE_PORT &= ~(1<<WAKE_PIN);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
INTERRUPT {
|
||||||
|
mrf->interrupt_handler(); // mrf24 object interrupt routine
|
||||||
|
mrf->check_flags();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <avr/io.h>
|
||||||
|
#include "mrf24j.h"
|
||||||
|
|
||||||
|
|
||||||
|
#if defined __AVR_ATmega328P__
|
||||||
|
#define SPI_DDR DDRB
|
||||||
|
#define SPI_PORT PORTB
|
||||||
|
#define SPI_SCK PB5
|
||||||
|
#define SPI_MISO PB4
|
||||||
|
#define SPI_MOSI PB3
|
||||||
|
#define SPI_CS PB2
|
||||||
|
#define RESET_DDR DDRB
|
||||||
|
#define RESET_PORT PORTB
|
||||||
|
#define RESET PB0
|
||||||
|
#define WAKE_PORT PORTB
|
||||||
|
#define WAKE_DDR DDRB
|
||||||
|
#define WAKE_PIN PB1
|
||||||
|
#define INTERRUPT ISR(INT0_vect)
|
||||||
|
#elif defined __AVR_ATmega32__ || defined __AVR_ATmega16__
|
||||||
|
#define SPI_PORT PORTB
|
||||||
|
#define SPI_DDR DDRB
|
||||||
|
#define SPI_SCK PB7
|
||||||
|
#define SPI_MOSI PB5
|
||||||
|
#define SPI_CS PB4
|
||||||
|
#define RESET_DDR DDRB
|
||||||
|
#define RESET_PORT PORTB
|
||||||
|
#define RESET PB0
|
||||||
|
#define INTERRUPT ISR(INT2_vect)
|
||||||
|
#elif defined RASPBERRYPI
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace driver
|
||||||
|
{
|
||||||
|
void init(Mrf24j *mrf);
|
||||||
|
uint8_t transfer(uint8_t data);
|
||||||
|
|
||||||
|
inline void cs_low() {SPI_PORT &= ~(1<<SPI_CS);}
|
||||||
|
|
||||||
|
inline void cs_high() {SPI_PORT |= (1<<SPI_CS);}
|
||||||
|
void wake();
|
||||||
|
void reset();
|
||||||
|
} // namespace spi
|
|
@ -0,0 +1,348 @@
|
||||||
|
/**
|
||||||
|
* mrf24j.cpp, Karl Palsson, 2011, karlp@tweak.net.au
|
||||||
|
* modified bsd license / apache license
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "mrf24j.h"
|
||||||
|
#include "driver.h"
|
||||||
|
#include <string.h>
|
||||||
|
#include <util/delay.h>
|
||||||
|
#include <avr/interrupt.h>
|
||||||
|
|
||||||
|
// aMaxPHYPacketSize = 127, from the 802.15.4-2006 standard.
|
||||||
|
static uint8_t rx_buf[127];
|
||||||
|
|
||||||
|
// essential for obtaining the data frame only
|
||||||
|
// bytes_MHR = 2 Frame control + 1 sequence number + 2 panid + 2 shortAddr Destination + 2 shortAddr Source
|
||||||
|
static int bytes_MHR = 9;
|
||||||
|
static int bytes_FCS = 2; // FCS length = 2
|
||||||
|
static int bytes_nodata = bytes_MHR + bytes_FCS; // no_data bytes in PHY payload, header length + FCS
|
||||||
|
|
||||||
|
static int ignoreBytes = 0; // bytes to ignore, some modules behaviour.
|
||||||
|
|
||||||
|
static bool bufPHY = false; // flag to buffer all bytes in PHY Payload, or not
|
||||||
|
|
||||||
|
volatile uint8_t flag_got_rx;
|
||||||
|
volatile uint8_t flag_got_tx;
|
||||||
|
|
||||||
|
static rx_info_t rx_info;
|
||||||
|
static tx_info_t tx_info;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor MRF24J Object.
|
||||||
|
*/
|
||||||
|
Mrf24j::Mrf24j() {
|
||||||
|
driver::init(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mrf24j::reset(void) {
|
||||||
|
driver::reset();
|
||||||
|
}
|
||||||
|
void Mrf24j::handlers(void (*rx_handler)(void), void (*tx_handler)(void)) {
|
||||||
|
this->rx_handler = rx_handler;
|
||||||
|
this->tx_handler = tx_handler;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
byte Mrf24j::read_short(byte address) {
|
||||||
|
driver::cs_low();
|
||||||
|
// 0 top for short addressing, 0 bottom for read
|
||||||
|
driver::transfer(address<<1 & 0b01111110);
|
||||||
|
byte ret = driver::transfer(0x00);
|
||||||
|
driver::cs_high();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte Mrf24j::read_long(word address) {
|
||||||
|
driver::cs_low();
|
||||||
|
byte ahigh = address >> 3;
|
||||||
|
byte alow = address << 5;
|
||||||
|
driver::transfer(0x80 | ahigh); // high bit for long
|
||||||
|
driver::transfer(alow);
|
||||||
|
byte ret = driver::transfer(0);
|
||||||
|
driver::cs_high();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Mrf24j::write_short(byte address, byte data) {
|
||||||
|
driver::cs_low();
|
||||||
|
// 0 for top short address, 1 bottom for write
|
||||||
|
driver::transfer((address<<1 & 0b01111110) | 0x01);
|
||||||
|
driver::transfer(data);
|
||||||
|
driver::cs_high();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mrf24j::write_long(word address, byte data) {
|
||||||
|
driver::cs_low();
|
||||||
|
byte ahigh = address >> 3;
|
||||||
|
byte alow = address << 5;
|
||||||
|
driver::transfer(0x80 | ahigh); // high bit for long
|
||||||
|
driver::transfer(alow | 0x10); // last bit for write
|
||||||
|
driver::transfer(data);
|
||||||
|
driver::cs_high();
|
||||||
|
}
|
||||||
|
|
||||||
|
word Mrf24j::get_pan(void) {
|
||||||
|
byte panh = read_short(MRF_PANIDH);
|
||||||
|
return panh << 8 | read_short(MRF_PANIDL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mrf24j::set_pan(word panid) {
|
||||||
|
write_short(MRF_PANIDH, panid >> 8);
|
||||||
|
write_short(MRF_PANIDL, panid & 0xff);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mrf24j::address16_write(word address16) {
|
||||||
|
write_short(MRF_SADRH, address16 >> 8);
|
||||||
|
write_short(MRF_SADRL, address16 & 0xff);
|
||||||
|
}
|
||||||
|
|
||||||
|
word Mrf24j::address16_read(void) {
|
||||||
|
byte a16h = read_short(MRF_SADRH);
|
||||||
|
return a16h << 8 | read_short(MRF_SADRL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple send 16, with acks, not much of anything.. assumes src16 and local pan only.
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
void Mrf24j::send16(word dest16, char * data) {
|
||||||
|
byte len = strlen(data); // get the length of the char* array
|
||||||
|
int i = 0;
|
||||||
|
write_long(i++, bytes_MHR); // header length
|
||||||
|
// +ignoreBytes is because some module seems to ignore 2 bytes after the header?!.
|
||||||
|
// default: ignoreBytes = 0;
|
||||||
|
write_long(i++, bytes_MHR+ignoreBytes+len);
|
||||||
|
|
||||||
|
// 0 | pan compression | ack | no security | no data pending | data frame[3 bits]
|
||||||
|
write_long(i++, 0b01100001); // first byte of Frame Control
|
||||||
|
// 16 bit source, 802.15.4 (2003), 16 bit dest,
|
||||||
|
write_long(i++, 0b10001000); // second byte of frame control
|
||||||
|
write_long(i++, 1); // sequence number 1
|
||||||
|
|
||||||
|
word panid = get_pan();
|
||||||
|
|
||||||
|
write_long(i++, panid & 0xff); // dest panid
|
||||||
|
write_long(i++, panid >> 8);
|
||||||
|
write_long(i++, dest16 & 0xff); // dest16 low
|
||||||
|
write_long(i++, dest16 >> 8); // dest16 high
|
||||||
|
|
||||||
|
word src16 = address16_read();
|
||||||
|
write_long(i++, src16 & 0xff); // src16 low
|
||||||
|
write_long(i++, src16 >> 8); // src16 high
|
||||||
|
|
||||||
|
// All testing seems to indicate that the next two bytes are ignored.
|
||||||
|
//2 bytes on FCS appended by TXMAC
|
||||||
|
i+=ignoreBytes;
|
||||||
|
for (int q = 0; q < len; q++) {
|
||||||
|
write_long(i++, data[q]);
|
||||||
|
}
|
||||||
|
// ack on, and go!
|
||||||
|
write_short(MRF_TXNCON, (1<<MRF_TXNACKREQ | 1<<MRF_TXNTRIG));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mrf24j::set_interrupts(void) {
|
||||||
|
// interrupts for rx and tx normal complete
|
||||||
|
write_short(MRF_INTCON, 0b11110110);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** use the 802.15.4 channel numbers..
|
||||||
|
*/
|
||||||
|
void Mrf24j::set_channel(byte channel) {
|
||||||
|
write_long(MRF_RFCON0, (((channel - 11) << 4) | 0x03));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mrf24j::init(void) {
|
||||||
|
|
||||||
|
// Seems a bit ridiculous when I use reset pin anyway
|
||||||
|
write_short(MRF_SOFTRST, 0x7); // from manual
|
||||||
|
while (read_short(MRF_SOFTRST) & 0x7 != 0) {
|
||||||
|
; // wait for soft reset to finish
|
||||||
|
}
|
||||||
|
|
||||||
|
write_short(MRF_PACON2, 0x98); // – Initialize FIFOEN = 1 and TXONTS = 0x6.
|
||||||
|
write_short(MRF_TXSTBL, 0x95); // – Initialize RFSTBL = 0x9.
|
||||||
|
|
||||||
|
write_long(MRF_RFCON0, 0x03); // – Initialize RFOPT = 0x03.
|
||||||
|
write_long(MRF_RFCON1, 0x01); // – Initialize VCOOPT = 0x02.
|
||||||
|
write_long(MRF_RFCON2, 0x80); // – Enable PLL (PLLEN = 1).
|
||||||
|
write_long(MRF_RFCON6, 0x90); // – Initialize TXFIL = 1 and 20MRECVR = 1.
|
||||||
|
write_long(MRF_RFCON7, 0x80); // – Initialize SLPCLKSEL = 0x2 (100 kHz Internal oscillator).
|
||||||
|
write_long(MRF_RFCON8, 0x10); // – Initialize RFVCO = 1.
|
||||||
|
write_long(MRF_SLPCON1, 0x21); // – Initialize CLKOUTEN = 1 and SLPCLKDIV = 0x01.
|
||||||
|
|
||||||
|
// Configuration for nonbeacon-enabled devices (see Section 3.8 “Beacon-Enabled and
|
||||||
|
// Nonbeacon-Enabled Networks”):
|
||||||
|
write_short(MRF_BBREG2, 0x80); // Set CCA mode to ED
|
||||||
|
write_short(MRF_CCAEDTH, 0x60); // – Set CCA ED threshold.
|
||||||
|
write_short(MRF_BBREG6, 0x40); // – Set appended RSSI value to RXFIFO.
|
||||||
|
set_interrupts();
|
||||||
|
set_channel(12);
|
||||||
|
// max power is by default.. just leave it...
|
||||||
|
// Set transmitter power - See “REGISTER 2-62: RF CONTROL 3 REGISTER (ADDRESS: 0x203)”.
|
||||||
|
write_short(MRF_RFCTL, 0x04); // – Reset RF state machine.
|
||||||
|
write_short(MRF_RFCTL, 0x00); // part 2
|
||||||
|
_delay_ms(1); // delay at least 192usec
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call this from within an interrupt handler connected to the MRFs output
|
||||||
|
* interrupt pin. It handles reading in any data from the module, and letting it
|
||||||
|
* continue working.
|
||||||
|
* Only the most recent data is ever kept.
|
||||||
|
*/
|
||||||
|
void Mrf24j::interrupt_handler(void) {
|
||||||
|
uint8_t last_interrupt = read_short(MRF_INTSTAT);
|
||||||
|
if (last_interrupt & MRF_I_RXIF) {
|
||||||
|
flag_got_rx++;
|
||||||
|
// read out the packet data...
|
||||||
|
cli();
|
||||||
|
rx_disable();
|
||||||
|
// read start of rxfifo for, has 2 bytes more added by FCS. frame_length = m + n + 2
|
||||||
|
uint8_t frame_length = read_long(0x300);
|
||||||
|
|
||||||
|
// buffer all bytes in PHY Payload
|
||||||
|
if(bufPHY){
|
||||||
|
int rb_ptr = 0;
|
||||||
|
for (int i = 0; i < frame_length; i++) { // from 0x301 to (0x301 + frame_length -1)
|
||||||
|
rx_buf[rb_ptr++] = read_long(0x301 + i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// buffer data bytes
|
||||||
|
int rd_ptr = 0;
|
||||||
|
// from (0x301 + bytes_MHR) to (0x301 + frame_length - bytes_nodata - 1)
|
||||||
|
for (int i = 0; i < rx_datalength(); i++) {
|
||||||
|
rx_info.rx_data[rd_ptr++] = read_long(0x301 + bytes_MHR + i);
|
||||||
|
}
|
||||||
|
|
||||||
|
rx_info.frame_length = frame_length;
|
||||||
|
// same as datasheet 0x301 + (m + n + 2) <-- frame_length
|
||||||
|
rx_info.lqi = read_long(0x301 + frame_length);
|
||||||
|
// same as datasheet 0x301 + (m + n + 3) <-- frame_length + 1
|
||||||
|
rx_info.rssi = read_long(0x301 + frame_length + 1);
|
||||||
|
|
||||||
|
rx_enable();
|
||||||
|
sei();
|
||||||
|
}
|
||||||
|
if (last_interrupt & MRF_I_TXNIF) {
|
||||||
|
flag_got_tx++;
|
||||||
|
uint8_t tmp = read_short(MRF_TXSTAT);
|
||||||
|
// 1 means it failed, we want 1 to mean it worked.
|
||||||
|
tx_info.tx_ok = !(tmp & ~(1 << TXNSTAT));
|
||||||
|
tx_info.retries = tmp >> 6;
|
||||||
|
tx_info.channel_busy = (tmp & (1 << CCAFAIL));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call this function periodically, it will invoke your nominated handlers
|
||||||
|
*/
|
||||||
|
void Mrf24j::check_flags(){
|
||||||
|
// TODO - we could check whether the flags are > 1 here, indicating data was lost?
|
||||||
|
if (flag_got_rx) {
|
||||||
|
flag_got_rx = 0;
|
||||||
|
this->rx_handler();
|
||||||
|
}
|
||||||
|
if (flag_got_tx) {
|
||||||
|
flag_got_tx = 0;
|
||||||
|
this->tx_handler();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set RX mode to promiscuous, or normal
|
||||||
|
*/
|
||||||
|
void Mrf24j::set_promiscuous(boolean enabled) {
|
||||||
|
if (enabled) {
|
||||||
|
write_short(MRF_RXMCR, 0x01);
|
||||||
|
} else {
|
||||||
|
write_short(MRF_RXMCR, 0x00);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rx_info_t * Mrf24j::get_rxinfo(void) {
|
||||||
|
return &rx_info;
|
||||||
|
}
|
||||||
|
|
||||||
|
tx_info_t * Mrf24j::get_txinfo(void) {
|
||||||
|
return &tx_info;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t * Mrf24j::get_rxbuf(void) {
|
||||||
|
return rx_buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Mrf24j::rx_datalength(void) {
|
||||||
|
return rx_info.frame_length - bytes_nodata;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mrf24j::set_ignoreBytes(int ib) {
|
||||||
|
// some modules behaviour
|
||||||
|
ignoreBytes = ib;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set bufPHY flag to buffer all bytes in PHY Payload, or not
|
||||||
|
*/
|
||||||
|
void Mrf24j::set_bufferPHY(boolean bp) {
|
||||||
|
bufPHY = bp;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean Mrf24j::get_bufferPHY(void) {
|
||||||
|
return bufPHY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set PA/LNA external control
|
||||||
|
*/
|
||||||
|
void Mrf24j::set_palna(boolean enabled) {
|
||||||
|
if (enabled) {
|
||||||
|
write_long(MRF_TESTMODE, 0x07); // Enable PA/LNA on MRF24J40MB module.
|
||||||
|
}else{
|
||||||
|
write_long(MRF_TESTMODE, 0x00); // Disable PA/LNA on MRF24J40MB module.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mrf24j::rx_flush(void) {
|
||||||
|
write_short(MRF_RXFLUSH, 0x01);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mrf24j::rx_disable(void) {
|
||||||
|
write_short(MRF_BBREG1, 0x04); // RXDECINV - disable receiver
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mrf24j::rx_enable(void) {
|
||||||
|
write_short(MRF_BBREG1, 0x00); // RXDECINV - enable receiver
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mrf24j::enable_wake() {
|
||||||
|
write_short(MRF_RXFLUSH, 0x60); // Enable WAKE pin and set polarity to active-high
|
||||||
|
write_short(MRF_WAKECON, 0x80); // Enable Immediate Wake-up mode
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mrf24j::sleep() {
|
||||||
|
write_short(MRF_SOFTRST, 0x04); // Perform a Power Management Reset
|
||||||
|
write_short(MRF_SLPACK, 0x80); // Put MRF24J40 to Sleep immediately
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mrf24j::wake() {
|
||||||
|
driver::wake();
|
||||||
|
write_short(MRF_RFCTL, 0x04); // RF State Machine reset
|
||||||
|
write_short(MRF_RFCTL, 0x00);
|
||||||
|
_delay_ms(2); // Delay 2 ms to allow 20 MHz main oscillator time to stabilize before transmitting or receiving.
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mrf24j::turbo() {
|
||||||
|
write_short(MRF_BBREG0, 0x01);
|
||||||
|
write_short(MRF_BBREG3, (1<<5)|(1<<4));
|
||||||
|
write_short(MRF_BBREG4, (1<<6));
|
||||||
|
write_short(MRF_SOFTRST, (1<<1));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mrf24j::set_power(byte level) {
|
||||||
|
write_short(MRF_RFCON3, level);
|
||||||
|
}
|
|
@ -0,0 +1,250 @@
|
||||||
|
/*
|
||||||
|
* File: mrf24j.h
|
||||||
|
* copyright Karl Palsson, karlp@tweak.net.au, 2011
|
||||||
|
* modified BSD License / apache license
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <avr/io.h>
|
||||||
|
|
||||||
|
typedef uint8_t byte;
|
||||||
|
typedef uint16_t word;
|
||||||
|
typedef bool boolean;
|
||||||
|
|
||||||
|
#ifndef LIB_MRF24J_H
|
||||||
|
#define LIB_MRF24J_H
|
||||||
|
|
||||||
|
#define MRF_RXMCR 0x00
|
||||||
|
#define MRF_PANIDL 0x01
|
||||||
|
#define MRF_PANIDH 0x02
|
||||||
|
#define MRF_SADRL 0x03
|
||||||
|
#define MRF_SADRH 0x04
|
||||||
|
#define MRF_EADR0 0x05
|
||||||
|
#define MRF_EADR1 0x06
|
||||||
|
#define MRF_EADR2 0x07
|
||||||
|
#define MRF_EADR3 0x08
|
||||||
|
#define MRF_EADR4 0x09
|
||||||
|
#define MRF_EADR5 0x0A
|
||||||
|
#define MRF_EADR6 0x0B
|
||||||
|
#define MRF_EADR7 0x0C
|
||||||
|
#define MRF_RXFLUSH 0x0D
|
||||||
|
//#define MRF_Reserved 0x0E
|
||||||
|
//#define MRF_Reserved 0x0F
|
||||||
|
#define MRF_ORDER 0x10
|
||||||
|
#define MRF_TXMCR 0x11
|
||||||
|
#define MRF_ACKTMOUT 0x12
|
||||||
|
#define MRF_ESLOTG1 0x13
|
||||||
|
#define MRF_SYMTICKL 0x14
|
||||||
|
#define MRF_SYMTICKH 0x15
|
||||||
|
#define MRF_PACON0 0x16
|
||||||
|
#define MRF_PACON1 0x17
|
||||||
|
#define MRF_PACON2 0x18
|
||||||
|
//#define MRF_Reserved 0x19
|
||||||
|
#define MRF_TXBCON0 0x1A
|
||||||
|
|
||||||
|
// TXNCON: TRANSMIT NORMAL FIFO CONTROL REGISTER (ADDRESS: 0x1B)
|
||||||
|
#define MRF_TXNCON 0x1B
|
||||||
|
#define MRF_TXNTRIG 0
|
||||||
|
#define MRF_TXNSECEN 1
|
||||||
|
#define MRF_TXNACKREQ 2
|
||||||
|
#define MRF_INDIRECT 3
|
||||||
|
#define MRF_FPSTAT 4
|
||||||
|
|
||||||
|
#define MRF_TXG1CON 0x1C
|
||||||
|
#define MRF_TXG2CON 0x1D
|
||||||
|
#define MRF_ESLOTG23 0x1E
|
||||||
|
#define MRF_ESLOTG45 0x1F
|
||||||
|
#define MRF_ESLOTG67 0x20
|
||||||
|
#define MRF_TXPEND 0x21
|
||||||
|
#define MRF_WAKECON 0x22
|
||||||
|
#define MRF_FRMOFFSET 0x23
|
||||||
|
// TXSTAT: TX MAC STATUS REGISTER (ADDRESS: 0x24)
|
||||||
|
#define MRF_TXSTAT 0x24
|
||||||
|
#define TXNRETRY1 7
|
||||||
|
#define TXNRETRY0 6
|
||||||
|
#define CCAFAIL 5
|
||||||
|
#define TXG2FNT 4
|
||||||
|
#define TXG1FNT 3
|
||||||
|
#define TXG2STAT 2
|
||||||
|
#define TXG1STAT 1
|
||||||
|
#define TXNSTAT 0
|
||||||
|
|
||||||
|
#define MRF_TXBCON1 0x25
|
||||||
|
#define MRF_GATECLK 0x26
|
||||||
|
#define MRF_TXTIME 0x27
|
||||||
|
#define MRF_HSYMTMRL 0x28
|
||||||
|
#define MRF_HSYMTMRH 0x29
|
||||||
|
#define MRF_SOFTRST 0x2A
|
||||||
|
//#define MRF_Reserved 0x2B
|
||||||
|
#define MRF_SECCON0 0x2C
|
||||||
|
#define MRF_SECCON1 0x2D
|
||||||
|
#define MRF_TXSTBL 0x2E
|
||||||
|
//#define MRF_Reserved 0x2F
|
||||||
|
#define MRF_RXSR 0x30
|
||||||
|
#define MRF_INTSTAT 0x31
|
||||||
|
#define MRF_INTCON 0x32
|
||||||
|
#define MRF_GPIO 0x33
|
||||||
|
#define MRF_TRISGPIO 0x34
|
||||||
|
#define MRF_SLPACK 0x35
|
||||||
|
#define MRF_RFCTL 0x36
|
||||||
|
#define MRF_SECCR2 0x37
|
||||||
|
#define MRF_BBREG0 0x38
|
||||||
|
#define MRF_BBREG1 0x39
|
||||||
|
#define MRF_BBREG2 0x3A
|
||||||
|
#define MRF_BBREG3 0x3B
|
||||||
|
#define MRF_BBREG4 0x3C
|
||||||
|
//#define MRF_Reserved 0x3D
|
||||||
|
#define MRF_BBREG6 0x3E
|
||||||
|
#define MRF_CCAEDTH 0x3F
|
||||||
|
|
||||||
|
#define MRF_RFCON0 0x200
|
||||||
|
#define MRF_RFCON1 0x201
|
||||||
|
#define MRF_RFCON2 0x202
|
||||||
|
#define MRF_RFCON3 0x203
|
||||||
|
#define MRF_RFCON5 0x205
|
||||||
|
#define MRF_RFCON6 0x206
|
||||||
|
#define MRF_RFCON7 0x207
|
||||||
|
#define MRF_RFCON8 0x208
|
||||||
|
#define MRF_SLPCAL0 0x209
|
||||||
|
#define MRF_SLPCAL1 0x20A
|
||||||
|
#define MRF_SLPCAL2 0x20B
|
||||||
|
#define MRF_RSSI 0x210
|
||||||
|
#define MRF_SLPCON0 0x211
|
||||||
|
#define MRF_SLPCON1 0x220
|
||||||
|
#define MRF_WAKETIMEL 0x222
|
||||||
|
#define MRF_WAKETIMEH 0x223
|
||||||
|
#define MRF_REMCNTL 0x224
|
||||||
|
#define MRF_REMCNTH 0x225
|
||||||
|
#define MRF_MAINCNT0 0x226
|
||||||
|
#define MRF_MAINCNT1 0x227
|
||||||
|
#define MRF_MAINCNT2 0x228
|
||||||
|
#define MRF_MAINCNT3 0x229
|
||||||
|
#define MRF_TESTMODE 0x22F
|
||||||
|
#define MRF_ASSOEADR1 0x231
|
||||||
|
#define MRF_ASSOEADR2 0x232
|
||||||
|
#define MRF_ASSOEADR3 0x233
|
||||||
|
#define MRF_ASSOEADR4 0x234
|
||||||
|
#define MRF_ASSOEADR5 0x235
|
||||||
|
#define MRF_ASSOEADR6 0x236
|
||||||
|
#define MRF_ASSOEADR7 0x237
|
||||||
|
#define MRF_ASSOSADR0 0x238
|
||||||
|
#define MRF_ASSOSADR1 0x239
|
||||||
|
#define MRF_UPNONCE0 0x240
|
||||||
|
#define MRF_UPNONCE1 0x241
|
||||||
|
#define MRF_UPNONCE2 0x242
|
||||||
|
#define MRF_UPNONCE3 0x243
|
||||||
|
#define MRF_UPNONCE4 0x244
|
||||||
|
#define MRF_UPNONCE5 0x245
|
||||||
|
#define MRF_UPNONCE6 0x246
|
||||||
|
#define MRF_UPNONCE7 0x247
|
||||||
|
#define MRF_UPNONCE8 0x248
|
||||||
|
#define MRF_UPNONCE9 0x249
|
||||||
|
#define MRF_UPNONCE10 0x24A
|
||||||
|
#define MRF_UPNONCE11 0x24B
|
||||||
|
#define MRF_UPNONCE12 0x24C
|
||||||
|
|
||||||
|
#define MRF_I_RXIF 0b00001000
|
||||||
|
#define MRF_I_TXNIF 0b00000001
|
||||||
|
|
||||||
|
#define MRF_S_WAKEPOL (1<<6)
|
||||||
|
#define MRF_S_PAKEPAD (1<<5)
|
||||||
|
#define MRF_S_IMMWAKE (1<<8)
|
||||||
|
#define MRF_S_SLPACK (1<<7)
|
||||||
|
#define MRF_S_RFRST (1<<2)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct _rx_info_t{
|
||||||
|
uint8_t frame_length;
|
||||||
|
uint8_t rx_data[116]; //max data length = (127 aMaxPHYPacketSize - 2 Frame control - 1 sequence number - 2 panid - 2 shortAddr Destination - 2 shortAddr Source - 2 FCS)
|
||||||
|
uint8_t lqi;
|
||||||
|
uint8_t rssi;
|
||||||
|
} rx_info_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Based on the TXSTAT register, but "better"
|
||||||
|
*/
|
||||||
|
typedef struct _tx_info_t{
|
||||||
|
uint8_t tx_ok:1;
|
||||||
|
uint8_t retries:2;
|
||||||
|
uint8_t channel_busy:1;
|
||||||
|
} tx_info_t;
|
||||||
|
|
||||||
|
class Mrf24j
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Mrf24j();
|
||||||
|
void reset(void);
|
||||||
|
void init(void);
|
||||||
|
void handlers(void (*rx_handler)(void), void (*tx_handler)(void));
|
||||||
|
|
||||||
|
byte read_short(byte address);
|
||||||
|
byte read_long(word address);
|
||||||
|
|
||||||
|
void write_short(byte address, byte data);
|
||||||
|
void write_long(word address, byte data);
|
||||||
|
|
||||||
|
word get_pan(void);
|
||||||
|
void set_pan(word panid);
|
||||||
|
|
||||||
|
void address16_write(word address16);
|
||||||
|
word address16_read(void);
|
||||||
|
|
||||||
|
void set_interrupts(void);
|
||||||
|
|
||||||
|
void set_promiscuous(boolean enabled);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the channel, using 802.15.4 channel numbers (11..26)
|
||||||
|
*/
|
||||||
|
void set_channel(byte channel);
|
||||||
|
|
||||||
|
void rx_enable(void);
|
||||||
|
void rx_disable(void);
|
||||||
|
|
||||||
|
/** If you want to throw away rx data */
|
||||||
|
void rx_flush(void);
|
||||||
|
|
||||||
|
rx_info_t * get_rxinfo(void);
|
||||||
|
|
||||||
|
tx_info_t * get_txinfo(void);
|
||||||
|
|
||||||
|
uint8_t * get_rxbuf(void);
|
||||||
|
|
||||||
|
int rx_datalength(void);
|
||||||
|
|
||||||
|
void set_ignoreBytes(int ib);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set bufPHY flag to buffer all bytes in PHY Payload, or not
|
||||||
|
*/
|
||||||
|
void set_bufferPHY(boolean bp);
|
||||||
|
|
||||||
|
boolean get_bufferPHY(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set PA/LNA external control
|
||||||
|
*/
|
||||||
|
void set_palna(boolean enabled);
|
||||||
|
|
||||||
|
void send16(word dest16, char * data);
|
||||||
|
|
||||||
|
void interrupt_handler(void);
|
||||||
|
|
||||||
|
void check_flags();
|
||||||
|
|
||||||
|
void enable_wake();
|
||||||
|
void sleep();
|
||||||
|
void wake();
|
||||||
|
void turbo();
|
||||||
|
void set_power(byte level);
|
||||||
|
|
||||||
|
private:
|
||||||
|
int _pin_reset;
|
||||||
|
int _pin_cs;
|
||||||
|
int _pin_int;
|
||||||
|
void (*rx_handler)(void);
|
||||||
|
void (*tx_handler)(void);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* LIB_MRF24J_H */
|
|
@ -0,0 +1,68 @@
|
||||||
|
/**
|
||||||
|
* Example code for using a microchip mrf24j40 module to send and receive
|
||||||
|
* packets using plain 802.15.4
|
||||||
|
* Requirements: 3 pins for spi, 3 pins for reset, chip select and interrupt
|
||||||
|
* notifications
|
||||||
|
* This example file is considered to be in the public domain
|
||||||
|
* Originally written by Karl Palsson, karlp@tweak.net.au, March 2011
|
||||||
|
*/
|
||||||
|
#define F_CPU 8000000UL
|
||||||
|
#include "../../src/mrf24j.h"
|
||||||
|
#include "../../lib/usart/src/usart.h"
|
||||||
|
#include <avr/interrupt.h>
|
||||||
|
#include <util/delay.h>
|
||||||
|
|
||||||
|
Mrf24j mrf;
|
||||||
|
|
||||||
|
void handle_rx();
|
||||||
|
void handle_tx();
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
usart::init(1000000);
|
||||||
|
|
||||||
|
mrf.reset();
|
||||||
|
mrf.init();
|
||||||
|
|
||||||
|
mrf.set_pan(0xcafe);
|
||||||
|
mrf.set_bufferPHY(true);
|
||||||
|
// This is _our_ address
|
||||||
|
mrf.address16_write(0x4202);
|
||||||
|
mrf.handlers(&handle_rx, &handle_tx);
|
||||||
|
mrf.turbo();
|
||||||
|
|
||||||
|
sei();
|
||||||
|
while(1) {
|
||||||
|
//printf("txxxing...\n\r");
|
||||||
|
//mrf.send16(0x4201, "abcd");
|
||||||
|
_delay_ms(5000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void handle_rx() {
|
||||||
|
printf("received a packet %i bytes long\n\r", mrf.get_rxinfo()->frame_length);
|
||||||
|
|
||||||
|
if(mrf.get_bufferPHY()){
|
||||||
|
printf("Packet data (PHY Payload):\n\r");
|
||||||
|
for (int i = 0; i < mrf.get_rxinfo()->frame_length; i++) {
|
||||||
|
printf("%x", mrf.get_rxbuf()[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// printf("\r\nASCII data (relevant data):\n\r");
|
||||||
|
// for (int i = 0; i < mrf.rx_datalength(); i++) {
|
||||||
|
// usart::put(mrf.get_rxinfo()->rx_data[i]);
|
||||||
|
// }
|
||||||
|
|
||||||
|
printf("\r\nLQI/RSSI=");
|
||||||
|
printf("%i/%i\n\r", mrf.get_rxinfo()->lqi, mrf.get_rxinfo()->rssi);
|
||||||
|
}
|
||||||
|
|
||||||
|
void handle_tx() {
|
||||||
|
if (mrf.get_txinfo()->tx_ok) {
|
||||||
|
printf("TX went ok, got ack\n\r");
|
||||||
|
} else {
|
||||||
|
printf("TX failed after %i retries\n\n\r", mrf.get_txinfo()->retries);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,78 @@
|
||||||
|
/**
|
||||||
|
* Example code for using a microchip mrf24j40 module to send and receive
|
||||||
|
* packets using plain 802.15.4
|
||||||
|
* Requirements: 3 pins for spi, 3 pins for reset, chip select and interrupt
|
||||||
|
* notifications
|
||||||
|
* This example file is considered to be in the public domain
|
||||||
|
* Originally written by Karl Palsson, karlp@tweak.net.au, March 2011
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define F_CPU 8000000UL
|
||||||
|
#include "../../src/mrf24j.h"
|
||||||
|
#include "../../lib/usart/src/usart.h"
|
||||||
|
#include "../../src/driver.h"
|
||||||
|
#include <avr/interrupt.h>
|
||||||
|
#include <util/delay.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Mrf24j mrf;
|
||||||
|
|
||||||
|
void handle_rx();
|
||||||
|
void handle_tx();
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
usart::init(1000000);
|
||||||
|
|
||||||
|
mrf.reset();
|
||||||
|
mrf.init();
|
||||||
|
|
||||||
|
mrf.set_pan(0xcafe);
|
||||||
|
// This is _our_ address
|
||||||
|
mrf.address16_write(0x4201);
|
||||||
|
mrf.handlers(&handle_rx, &handle_tx);
|
||||||
|
//mrf.enable_wake();
|
||||||
|
mrf.set_bufferPHY(true);
|
||||||
|
mrf.turbo();
|
||||||
|
mrf.set_power(0b1100000);
|
||||||
|
//mrf.sleep();
|
||||||
|
sei();
|
||||||
|
while(1) {
|
||||||
|
printf("txxxing...\n\r");
|
||||||
|
//mrf.wake();
|
||||||
|
mrf.send16(0x4202, "Tx Hello");
|
||||||
|
|
||||||
|
_delay_ms(2000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void handle_rx() {
|
||||||
|
printf("received a packet %i bytes long\n\r", mrf.get_rxinfo()->frame_length);
|
||||||
|
|
||||||
|
if(mrf.get_bufferPHY()){
|
||||||
|
printf("Packet data (PHY Payload):\n\r");
|
||||||
|
for (int i = 0; i < mrf.get_rxinfo()->frame_length; i++) {
|
||||||
|
printf("%i", mrf.get_rxbuf()[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// printf("\r\nASCII data (relevant data):\n\r");
|
||||||
|
// for (int i = 0; i < mrf.rx_datalength(); i++) {
|
||||||
|
// usart::put(mrf.get_rxinfo()->rx_data[i]);
|
||||||
|
// }
|
||||||
|
|
||||||
|
printf("\r\nLQI/RSSI=");
|
||||||
|
printf("%i/%i\n\r", mrf.get_rxinfo()->lqi, mrf.get_rxinfo()->rssi);
|
||||||
|
}
|
||||||
|
|
||||||
|
void handle_tx() {
|
||||||
|
if (mrf.get_txinfo()->tx_ok) {
|
||||||
|
printf("TX went ok, got ack\n\r");
|
||||||
|
} else {
|
||||||
|
printf("TX failed after %i retries\n\n\r", mrf.get_txinfo()->retries);
|
||||||
|
}
|
||||||
|
printf("Sleeping\n\r");
|
||||||
|
//mrf.sleep();
|
||||||
|
}
|
Loading…
Reference in New Issue