main.c (for reading the registers)
//Test routine
delay_us(500000);
mirf_init();
mirf_config();
delay_us(500000);
//spi_transmit_sync(mydata,buffersize); // Write payload
//delay_us(1);
//spi_transfer_sync(buffer,buffer,buffersize); // Read payload
//delay_us(1);
//mirf_read_register(5,1,2);
nrf_read_register(CONFIG,2); //Read registers
mirf_data_ready(); //Status
mirf.c
#include "io.h"
#include "buffer.h"
#include "rprintf.h"
#include "a2d.h"
#include "uart2.h"
#include "signal.h"
#include "spi.h"
#include "timer128.h"
#include "mirf.h"
#include "interrupt.h"
#include "global.h"
#include "mirf.h"
#include "nRF24L01.h"
#include "spi.h"
#include <avr/io.h>
#include <avr/interrupt.h>
// Defines for setting the MiRF registers for transmitting or receiving mode
#define TX_POWERUP mirf_config_register(CONFIG, mirf_CONFIG | ( (1<<PWR_UP) | (0<<PRIM_RX) ) )
#define RX_POWERUP mirf_config_register(CONFIG, mirf_CONFIG | ( (1<<PWR_UP) | (1<<PRIM_RX) ) )
//#define __AVR_ATmega128__
// Flag which denotes transmitting mode
volatile uint8_t PTX;
void mirf_init()
// Initializes pins ans interrupt to communicate with the MiRF module
// Should be called in the early initializing phase at startup.
{
// Define CSN and CE as Output and set them to default
DDRB |= ((1<<CSN)|(1<<CE));
mirf_CE_lo;
mirf_CSN_hi;
#if defined(__AVR_ATmega8__)
// Initialize external interrupt 0 (PD2)
MCUCR = ((1<<ISC11)|(0<<ISC10)|(1<<ISC01)|(0<<ISC00)); // Set external interupt on falling edge
GICR = ((0<<INT1)|(1<<INT0)); // Activate INT0
#endif // __AVR_ATmega8__
#if defined(__AVR_ATmega168__)
// Initialize external interrupt on port PD6 (PCINT22)
//DDRB &= ~(1<<PD6);
//PCMSK2 = (1<<PCINT22);
//PCICR = (1<<PCIE2);
#endif // __AVR_ATmega168__
#if defined(__AVR_ATmega128__)
// Initialize external interrupt on port PE7
DDRE &= ~(1<<PE7);
EICRB = ((1<<ISC71)|(0<<ISC70));
//EIMSK = (1<<INT7_vect);
EIMSK = (1<<INT7);
#endif // __AVR_ATmega128__
// Initialize spi module
spi_init();
}
void mirf_config()
// Sets the important registers in the MiRF module and powers the module
// in receiving mode
{
// Set RF channel
mirf_config_register(RF_CH,mirf_CH);
//mirf_config_register(CONFIG,5); //test of writing to register
// Set length of incoming payload
mirf_config_register(RX_PW_P0, mirf_PAYLOAD);
// Start receiver
PTX = 0; // Start in receiving mode
RX_POWERUP; // Power up in receiving mode
//delay_us(100);
mirf_CE_hi; // Listening for pakets
}
void mirf_set_RADDR(uint8_t * adr)
// Sets the receiving address
{
mirf_CE_lo;
mirf_write_register(RX_ADDR_P0,adr,5);
mirf_CE_hi;
}
void mirf_set_TADDR(uint8_t * adr)
// Sets the transmitting address
{
mirf_write_register(TX_ADDR, adr,5);
}
#if defined(__AVR_ATmega8__)
SIGNAL(SIG_INTERRUPT0)
#endif // __AVR_ATmega8__
#if defined(__AVR_ATmega168__)
SIGNAL(SIG_PIN_CHANGE2)
#endif // __AVR_ATmega168__
#if defined(__AVR_ATmega128__)
SIGNAL(SIG_INTERRUPT7)
#endif // __AVR_ATmega128__
// Interrupt handler
{
uint8_t status;
// If still in transmitting mode then finish transmission
if (PTX) {
// Read MiRF status
mirf_CSN_lo; // Pull down chip select
status = spi_fast_shift(NOP); // Read status register
mirf_CSN_hi; // Pull up chip select
mirf_CE_lo; // Deactivate transreceiver
RX_POWERUP; // Power up in receiving mode
mirf_CE_hi; // Listening for pakets
PTX = 0; // Set to receiving mode
// Reset status register for further interaction
mirf_config_register(STATUS,(1<<TX_DS)|(1<<MAX_RT)); // Reset status register
}
}
extern uint8_t mirf_data_ready()
// Checks if data is available for reading
{
if (PTX) return 0;
uint8_t status;
// Read MiRF status
mirf_CSN_lo; // Pull down chip select
status = spi_fast_shift(0x00); // Read status register
mirf_CSN_hi; // Pull up chip select
rprintf("Status register 0: %d\r\n", status);
return status & (1<<RX_DR);
}
extern void mirf_get_data(uint8_t * data)
// Reads mirf_PAYLOAD bytes into data array
{
mirf_CSN_lo; // Pull down chip select
spi_fast_shift( R_RX_PAYLOAD ); // Send cmd to read rx payload
spi_transfer_sync(data,data,mirf_PAYLOAD); // Read payload
mirf_CSN_hi; // Pull up chip select
mirf_config_register(STATUS,(1<<RX_DR)); // Reset status register
}
void mirf_config_register(uint8_t reg, uint8_t value)
// Clocks only one byte into the given MiRF register
{
mirf_CSN_lo;
spi_fast_shift(W_REGISTER | (REGISTER_MASK & reg));
spi_fast_shift(value);
mirf_CSN_hi;
}
void nrf_read_register(uint8_t reg,uint8_t len)
{
//RX_POWERUP;
delay_us(50000);
mirf_CSN_lo;
spi_fast_shift(R_REGISTER | (REGISTER_MASK & reg)); //Status
nrf_transfer_sync(reg, len); //Read register
mirf_CSN_hi;
delay_us(500000);
rprintf("Value register %d: %d\r\n",reg, SPDR);
}
void mirf_read_register(uint8_t reg, uint8_t * value, uint8_t len)
// Reads an array of bytes from the given start position in the MiRF registers.
{
mirf_CSN_lo;
spi_fast_shift(R_REGISTER | (REGISTER_MASK & reg));
spi_transfer_sync(value,value,len);
mirf_CSN_hi;
}
void mirf_write_register(uint8_t reg, uint8_t * value, uint8_t len)
// Writes an array of bytes into inte the MiRF registers.
{
mirf_CSN_lo;
spi_fast_shift(W_REGISTER | (REGISTER_MASK & reg));
spi_transmit_sync(value,len);
mirf_CSN_hi;
}
void mirf_send(uint8_t * value, uint8_t len)
// Sends a data package to the default address. Be sure to send the correct
// amount of bytes as configured as payload on the receiver.
{
//rprintf("test");
while (PTX) {} // Wait until last paket is send
mirf_CE_lo;
PTX = 1; // Set to transmitter mode
TX_POWERUP; // Power up
mirf_CSN_lo; // Pull down chip select
spi_fast_shift( FLUSH_TX ); // Write cmd to flush tx fifo
mirf_CSN_hi; // Pull up chip select
mirf_CSN_lo; // Pull down chip select
spi_fast_shift( W_TX_PAYLOAD ); // Write cmd to write payload
spi_transmit_sync(value,len); // Write payload
mirf_CSN_hi; // Pull up chip select
mirf_CE_hi; // Start transmission
PTX = 0;
}
mirf.h
#ifndef _MIRF_H_
#define _MIRF_H_
#include <avr/io.h>
// Mirf settings
#define mirf_CH 22
#define mirf_PAYLOAD 16
#define mirf_CONFIG ( (1<<MASK_RX_DR) | (1<<EN_CRC) | (0<<CRCO) )
// Pin definitions for chip select and chip enabled of the MiRF module
#define CE PA3
#define CSN PB0
// Definitions for selecting and enabling MiRF module
#define mirf_CSN_hi PORTB |= (1<<CSN);
#define mirf_CSN_lo PORTB &= ~(1<<CSN);
#define mirf_CE_hi PORTA |= (1<<CE);
#define mirf_CE_lo PORTA &= ~(1<<CE);
// Public standart functions
extern void mirf_init();
extern void mirf_config();
extern void mirf_send(uint8_t * value, uint8_t len);
extern void mirf_set_RADDR(uint8_t * adr);
extern void mirf_set_TADDR(uint8_t * adr);
extern uint8_t mirf_data_ready();
extern void mirf_get_data(uint8_t * data);
// Public extended functions
extern void mirf_config_register(uint8_t reg, uint8_t value);
extern void mirf_read_register(uint8_t reg, uint8_t * value, uint8_t len);
extern void mirf_write_register(uint8_t reg, uint8_t * value, uint8_t len);
#endif /* _MIRF_H_ */
spi.c
#include "spi.h"
#include <avr/io.h>
#include <avr/interrupt.h>
#define PORT_SPI PORTB
#define DDR_SPI DDRB
#define DD_MISO DDB3
#define DD_MOSI DDB2
#define DD_SS DDB0 //CSN
#define DD_SCK DDB1
void spi_init()
// Initialize pins for spi communication
{
DDR_SPI &= ~((1<<DD_MOSI)|(1<<DD_MISO)|(1<<DD_SS)|(1<<DD_SCK));
// Define the following pins as output
DDR_SPI |= ((1<<DD_MOSI)|(1<<DD_SS)|(1<<DD_SCK));
SPCR = ((1<<SPE)| // SPI Enable
(0<<SPIE)| // SPI Interupt Enable
(0<<DORD)| // Data Order (0:MSB first / 1:LSB first)
(1<<MSTR)| // Master/Slave select
(1<<SPR1)|(0<<SPR0)| // SPI Clock Rate
(0<<CPOL)| // Clock Polarity (0:SCK low / 1:SCK hi when idle)
(0<<CPHA)); // Clock Phase (0:leading / 1:trailing edge sampling)
SPSR = (0<<SPI2X); // Double Clock Rate
}
void nrf_transfer_sync (uint8_t * dataout, uint8_t len)
{
uint8_t i;
for (i = 1; i < len; i++) {
SPDR = 1 ;
while((SPSR & (1<<SPIF))==0);
dataout[i] = SPDR;
}
return SPDR;
}
void spi_transfer_sync (uint8_t * dataout, uint8_t * datain, uint8_t len)
// Shift full array through target device
{
uint8_t i;
for (i = 0; i < len; i++) {
SPDR = dataout[i];
while((SPSR & (1<<SPIF))==0);
datain[i] = SPDR;
}
return SPDR;
}
void spi_transmit_sync (uint8_t * dataout, uint8_t len)
// Shift full array to target device without receiving any byte
{
uint8_t i;
for (i = 0; i < len; i++) {
SPDR = dataout[i];
while((SPSR & (1<<SPIF))==0);
}
}
uint8_t spi_fast_shift (uint8_t data)
// Clocks only one byte to target device and returns the received one
{
SPDR = data;
while((SPSR & (1<<SPIF))==0);
return SPDR;
}
nRF24L01.h
/* Memory Map */
#define CONFIG 0x00
#define EN_AA 0x01
#define EN_RXADDR 0x02
#define SETUP_AW 0x03
#define SETUP_RETR 0x04
#define RF_CH 0x05
#define RF_SETUP 0x06
#define STATUS 0x07
#define OBSERVE_TX 0x08
#define CD 0x09
#define RX_ADDR_P0 0x0A
#define RX_ADDR_P1 0x0B
#define RX_ADDR_P2 0x0C
#define RX_ADDR_P3 0x0D
#define RX_ADDR_P4 0x0E
#define RX_ADDR_P5 0x0F
#define TX_ADDR 0x10
#define RX_PW_P0 0x11
#define RX_PW_P1 0x12
#define RX_PW_P2 0x13
#define RX_PW_P3 0x14
#define RX_PW_P4 0x15
#define RX_PW_P5 0x16
#define FIFO_STATUS 0x17
/* Bit Mnemonics */
#define MASK_RX_DR 6
#define MASK_TX_DS 5
#define MASK_MAX_RT 4
#define EN_CRC 3
#define CRCO 2
#define PWR_UP 1
#define PRIM_RX 0
#define ENAA_P5 5
#define ENAA_P4 4
#define ENAA_P3 3
#define ENAA_P2 2
#define ENAA_P1 1
#define ENAA_P0 0
#define ERX_P5 5
#define ERX_P4 4
#define ERX_P3 3
#define ERX_P2 2
#define ERX_P1 1
#define ERX_P0 0
#define AW 0
#define ARD 4
#define ARC 0
#define PLL_LOCK 4
#define RF_DR 3
#define RF_PWR 1
#define LNA_HCURR 0
#define RX_DR 6
#define TX_DS 5
#define MAX_RT 4
#define RX_P_NO 1
#define TX_FULL 0
#define PLOS_CNT 4
#define ARC_CNT 0
#define TX_REUSE 6
#define FIFO_FULL 5
#define TX_EMPTY 4
#define RX_FULL 1
#define RX_EMPTY 0
/* Instruction Mnemonics */
#define R_REGISTER 0x00
#define W_REGISTER 0x20
#define REGISTER_MASK 0x1F
#define R_RX_PAYLOAD 0x61
#define W_TX_PAYLOAD 0xA0
#define FLUSH_TX 0xE1
#define FLUSH_RX 0xE2
#define REUSE_TX_PL 0xE3
#define NOP 0xFF