Browse Source

initial commit

master
Olaf Rempel 5 years ago
commit
ecc9bd42cf
7 changed files with 1621 additions and 0 deletions
  1. +1
    -0
      .gitignore
  2. +60
    -0
      Makefile
  3. +455
    -0
      funkboot.c
  4. +438
    -0
      rfm12.c
  5. +39
    -0
      rfm12.h
  6. +575
    -0
      rfm12_hw.h
  7. +53
    -0
      target.h

+ 1
- 0
.gitignore View File

@@ -0,0 +1 @@
build

+ 60
- 0
Makefile View File

@@ -0,0 +1,60 @@
CC := avr-gcc
LD := avr-ld
OBJCOPY := avr-objcopy
OBJDUMP := avr-objdump
SIZE := avr-size

TARGET = funkboot
SOURCE = $(wildcard *.c)
BUILD_DIR = build

CONFIG = funkstuff168

AVRDUDE_PROG := -c avr910 -b 115200 -P /dev/ispprog
#AVRDUDE_PROG := -c dragon_isp -P usb

# ---------------------------------------------------------------------------

ifeq ($(CONFIG), funkstuff168)
# (ext. crystal 16MHz, 2.7V BOD)
MCU = atmega168
AVRDUDE_MCU=m168 -F

AVRDUDE_FUSES=lfuse:w:0xff:m hfuse:w:0xdd:m efuse:w:0x00:m
BOOTLOADER_START=0x3800
endif

# ---------------------------------------------------------------------------

CFLAGS = -pipe -g -Os -mmcu=$(MCU) -Wall -fdata-sections -ffunction-sections
CFLAGS += -Wa,-adhlns=$(BUILD_DIR)/$(*D)/$(*F).lst -MMD -MP -MF $(BUILD_DIR)/$(*D)/$(*F).d
CFLAGS += -DBOOTLOADER_START=$(BOOTLOADER_START) -DCONFIG_$(CONFIG)=1
LDFLAGS = -Wl,-Map,$(@:.elf=.map),--cref,--relax,--gc-sections,--section-start=.text=$(BOOTLOADER_START)

# ---------------------------------------------------------------------------

$(TARGET): $(BUILD_DIR)/$(TARGET).elf
@$(SIZE) -B -x --mcu=$(MCU) $<

$(BUILD_DIR)/$(TARGET).elf: $(patsubst %,$(BUILD_DIR)/%,$(SOURCE:.c=.o))
@echo " Linking file: $@"
@$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^
@$(OBJDUMP) -h -S $@ > $(@:.elf=.lss)
@$(OBJCOPY) -j .text -j .data -O ihex $@ $(@:.elf=.hex)
@$(OBJCOPY) -j .text -j .data -O binary $@ $(@:.elf=.bin)

$(BUILD_DIR)/%.o: %.c $(MAKEFILE_LIST)
@echo " Building file: $<"
@$(shell test -d $(BUILD_DIR)/$(*D) || mkdir -p $(BUILD_DIR)/$(*D))
@$(CC) $(CFLAGS) -o $@ -c $<

include $(shell find $(BUILD_DIR) -name \*.d 2> /dev/null)

clean:
rm -rf $(BUILD_DIR)

install: $(BUILD_DIR)/$(TARGET).elf
avrdude $(AVRDUDE_PROG) -p $(AVRDUDE_MCU) -U flash:w:$(<:.elf=.hex)

fuses:
avrdude $(AVRDUDE_PROG) -p $(AVRDUDE_MCU) $(patsubst %,-U %, $(AVRDUDE_FUSES))

+ 455
- 0
funkboot.c View File

@@ -0,0 +1,455 @@
/***************************************************************************
* Copyright (C) 11/2014 by Olaf Rempel *
* razzor@kopf-tisch.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; version 2 of the License, *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/boot.h>
#include <avr/pgmspace.h>

#include <string.h>

#include "target.h"
#include "rfm12.h"

/* *********************************************************************** */

#define BOOTWAIT_EXPIRED 0x0000
#define BOOTWAIT_INTERRUPTED 0xFFFF

#define MSG_TYPE_REQUEST 0x00 /* master -> slave req */
#define MSG_TYPE_CONFIRMATION 0x40 /* master -> slave rsp */
#define MSG_TYPE_INDICATION 0x80 /* slave -> master req */
#define MSG_TYPE_RESPONSE 0xC0 /* slave -> master rsp */
#define MSG_TYPE_MASK 0xC0
#define MSG_CMD_MASK 0x3F

#define MSG_CMD_SWITCHAPP_REQUEST (MSG_TYPE_REQUEST | 0x20)
#define MSG_CMD_SWITCHAPP_RESPONSE (MSG_TYPE_RESPONSE | 0x20)

#define MSG_CMD_VERSION_REQUEST (MSG_TYPE_REQUEST | 0x21)
#define MSG_CMD_VERSION_RESPONSE (MSG_TYPE_RESPONSE | 0x21)

#define MSG_CMD_CHIPINFO_REQUEST (MSG_TYPE_REQUEST | 0x22)
#define MSG_CMD_CHIPINFO_RESPONSE (MSG_TYPE_RESPONSE | 0x22)

#define MSG_CMD_READ_REQUEST (MSG_TYPE_REQUEST | 0x23)
#define MSG_CMD_READ_RESPONSE (MSG_TYPE_RESPONSE | 0x23)

#define MSG_CMD_WRITE_REQUEST (MSG_TYPE_REQUEST | 0x24)
#define MSG_CMD_WRITE_RESPONSE (MSG_TYPE_RESPONSE | 0x24)

#define CAUSE_SUCCESS 0x00
#define CAUSE_NOT_SUPPORTED 0xF0
#define CAUSE_INVALID_PARAMETER 0xF1
#define CAUSE_UNSPECIFIED_ERROR 0xFF

#define BOOTMODE_BOOTLOADER 0x00
#define BOOTMODE_APPLICATION 0x80

#define MEMTYPE_FLASH 0x01
#define MEMTYPE_EEPROM 0x02

/* *********************************************************************** */

struct bootloader_msg
{
uint8_t command;
uint8_t seqnum;
uint8_t cause;

union {
struct {
uint8_t app;
} switchapp;

struct {
uint8_t data[16];
} version;

struct {
uint8_t data[8];
} chipinfo;

struct {
uint16_t address;
uint8_t mem_type;
uint8_t size;
} read_req;

struct {
uint8_t data[32];
} read_rsp;

struct {
uint16_t address;
uint8_t mem_type;
uint8_t size;
uint8_t data[32];
} write_req;
} p;
};

/* *********************************************************************** */

#define LED_RX 0
#define LED_TX 1

static uint8_t led_timer[2];
volatile static uint8_t clock_tick;

const static uint8_t version_info[16] = VERSION_STRING;
const static uint8_t chip_info[8] = {
SIGNATURE_BYTES,

SPM_PAGESIZE,

((BOOTLOADER_START) >> 8) & 0xFF,
(BOOTLOADER_START) & 0xFF,
((E2END +1) >> 8 & 0xFF),
(E2END +1) & 0xFF
};


/* *********************************************************************** */


static void read_flash(uint8_t *data, uint16_t address, uint8_t size)
{
while (size--)
{
*data++ = pgm_read_byte_near(address++);
}
} /* read_flash_byte */


static void write_flash(uint8_t *data, uint16_t address, uint8_t size)
{
static uint16_t pagestart;
static uint8_t pagesize;

if ((address & (SPM_PAGESIZE -1)) == 0x00)
{
pagestart = address;
pagesize = SPM_PAGESIZE;

boot_page_erase(pagestart);
boot_spm_busy_wait();
}

while (size && pagesize)
{
uint16_t dataword;

dataword = (*data++);
dataword |= (*data++) << 8;
boot_page_fill(address, dataword);

address += 2;
pagesize -= 2;
size -= 2;
}

if (pagesize == 0)
{
boot_page_write(pagestart);
boot_spm_busy_wait();
boot_rww_enable();
}
} /* write_flash */


static void read_eeprom(uint8_t *data, uint16_t address, uint8_t size)
{
while (size--)
{
EEARL = address;
EEARH = (address >> 8);
EECR |= (1<<EERE);

address++;
*data++ = EEDR;
}
} /* read_eeprom */


static void write_eeprom(uint8_t *data, uint16_t address, uint8_t size)
{
while (size--)
{
EEARL = address;
EEARH = (address >> 8);
EEDR = *data++;

address++;

cli();
#if defined (__AVR_ATmega168__)
EECR |= (1<<EEMPE);
EECR |= (1<<EEPE);
#endif
sei();

eeprom_busy_wait();
}
} /* write_eeprom */


ISR(TIMER0_OVF_vect)
{
TCNT0 = TIMER_RELOAD;

clock_tick = 1;
} /* TIMER0_OVF_vect */


static void (*jump_to_app)(void) __attribute__ ((noreturn)) = 0x0000;


#if defined(__AVR_ATmega168__)
/*
* For newer devices the watchdog timer remains active even after a
* system reset. So disable it as soon as possible.
* automagically called on startup
*/
void disable_wdt_timer(void) __attribute__((naked, section(".init3")));
void disable_wdt_timer(void)
{
MCUSR = 0;
WDTCSR = (1<<WDCE) | (1<<WDE);
WDTCSR = (0<<WDE);
} /* disable_wdt_timer */
#endif


int main(void) __attribute__ ((noreturn));
int main(void)
{
/* init LEDs */
LED_INIT();

#if defined (__AVR_ATmega168__)
/* move interrupt-vectors to bootloader */
MCUCR = (1<<IVCE);
MCUCR = (1<<IVSEL);

/* timer0, FCPU/64, overflow interrupt */
TCCR0B = (1<<CS01) | (1<<CS00);
TIMSK0 = (1<<TOIE0);
#endif

rfm12_init(RFM12_ADDRESS);

sei();

uint16_t boot_timeout = TIMEOUT;
while (1)
{
if (clock_tick == 0)
continue;

clock_tick = 0;

if (led_timer[LED_RX] > 0)
{
led_timer[LED_RX]--;
LED_GN_ON();
}
else
{
LED_GN_OFF();
}

if (led_timer[LED_TX] > 0)
{
led_timer[LED_TX]--;
LED_RT_ON();
}
else
{
LED_RT_OFF();
}

/* do periodic work (wait for 5 ticks silence before start TX) */
rfm12_tick(5);

/* get TX buffer */
struct rfm12_packet *rsp_pkt = rfm12_get_txpkt();

if (boot_timeout == BOOTWAIT_EXPIRED)
{
/* timeout elapsed and TX buffer available (tx completed) -> start application */
if (rsp_pkt != NULL)
{
break;
}
}
else if (boot_timeout != BOOTWAIT_INTERRUPTED)
{
boot_timeout--;
}

if ((boot_timeout & 0x3F) == 0)
{
led_timer[LED_TX] = 5;
}

/* get RX data */
struct rfm12_packet *req_pkt = rfm12_get_rxpkt();
if (req_pkt == NULL)
{
/* no data available */
continue;
}
else
{
led_timer[LED_RX] = 5;

/* no tx buffer available, ignore request */
if (rsp_pkt == NULL)
{
rfm12_clear_rx();
continue;
}
}

/* stay in bootloader */
boot_timeout = BOOTWAIT_INTERRUPTED;

struct bootloader_msg *req_msg = (struct bootloader_msg *)req_pkt->data;
struct bootloader_msg *rsp_msg = (struct bootloader_msg *)rsp_pkt->data;

/* retransmitted request -> retransmit response */
if ((req_pkt->source_address == rsp_pkt->dest_address) &&
((req_msg->command & MSG_CMD_MASK) == (rsp_msg->command & MSG_CMD_MASK)) &&
(req_msg->seqnum == rsp_msg->seqnum)
)
{
/* RX packet no longer needed */
rfm12_clear_rx();

/* transmit response */
if (rfm12_start_tx())
{
led_timer[LED_TX] = 5;
}

continue;
}

rsp_pkt->dest_address = req_pkt->source_address;
rsp_pkt->data_length = 3;
rsp_msg->command = req_msg->command | MSG_TYPE_RESPONSE;
rsp_msg->seqnum = req_msg->seqnum;
rsp_msg->cause = CAUSE_SUCCESS;

switch (req_msg->command)
{
case MSG_CMD_SWITCHAPP_REQUEST:
if (req_msg->p.switchapp.app == BOOTMODE_APPLICATION)
{
boot_timeout = BOOTWAIT_EXPIRED;
}
else if (req_msg->p.switchapp.app != BOOTMODE_BOOTLOADER)
{
rsp_msg->cause = CAUSE_INVALID_PARAMETER;
}
break;

case MSG_CMD_VERSION_REQUEST:
memcpy(rsp_msg->p.version.data, version_info, sizeof(rsp_msg->p.version.data));
rsp_pkt->data_length += sizeof(rsp_msg->p.version.data);
break;

case MSG_CMD_CHIPINFO_REQUEST:
memcpy(rsp_msg->p.chipinfo.data, chip_info, sizeof(rsp_msg->p.chipinfo.data));
rsp_pkt->data_length += sizeof(rsp_msg->p.chipinfo.data);
break;

case MSG_CMD_READ_REQUEST:
if (req_msg->p.read_req.mem_type == MEMTYPE_FLASH)
{
read_flash(rsp_msg->p.read_rsp.data,
req_msg->p.read_req.address,
req_msg->p.read_req.size);

rsp_pkt->data_length += req_msg->p.read_req.size;
}
else if (req_msg->p.read_req.mem_type == MEMTYPE_EEPROM)
{
read_eeprom(rsp_msg->p.read_rsp.data,
req_msg->p.read_req.address,
req_msg->p.read_req.size);

rsp_pkt->data_length += req_msg->p.read_req.size;
}
else
{
rsp_msg->cause = CAUSE_INVALID_PARAMETER;
}
break;

case MSG_CMD_WRITE_REQUEST:
if (req_msg->p.write_req.mem_type == MEMTYPE_FLASH)
{
write_flash(req_msg->p.write_req.data,
req_msg->p.write_req.address,
req_msg->p.write_req.size);
}
else if (req_msg->p.write_req.mem_type == MEMTYPE_EEPROM)
{
write_eeprom(req_msg->p.write_req.data,
req_msg->p.write_req.address,
req_msg->p.write_req.size);
}
else
{
rsp_msg->cause = CAUSE_INVALID_PARAMETER;
}
break;

default:
rsp_msg->cause = CAUSE_NOT_SUPPORTED;
break;
}

/* RX packet no longer needed */
rfm12_clear_rx();

/* transmit response */
if (rfm12_start_tx())
{
led_timer[LED_TX] = 5;
}
}

cli();

#if defined (__AVR_ATmega168__)
/* disable timer0 */
TIMSK0 = 0x00;
TCCR0B = 0x00;

/* move interrupt vectors back to application */
MCUCR = (1<<IVCE);
MCUCR = (0<<IVSEL);
#endif

LED_OFF();

jump_to_app();
} /* main */

+ 438
- 0
rfm12.c View File

@@ -0,0 +1,438 @@
/***************************************************************************
* Copyright (C) 11/2014 by Olaf Rempel *
* razzor@kopf-tisch.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; version 2 of the License, *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <util/crc16.h>

#include "target.h"
#include "rfm12_hw.h"
#include "rfm12.h"

/* *********************************************************************** */

#define RFM12_PREAMBLE 0xAA
#define RFM12_SYNC_LSB 0xD4
#define RFM12_SYNC_MSB 0x2D

#define RFM12_BASEBAND RFM12_BAND_868
#define RFM12_XTAL_LOAD RFM12_XTAL_11_5PF
#define RFM12_FREQUENCY_CALC RFM12_FREQUENCY_CALC_868
#define RFM12_FREQUENCY 869800000UL
#define RFM12_DATARATE RFM12_DATARATE_CALC_HIGH(19200.0)
#define RFM12_FILTER_BW RFM12_RXCTRL_BW_400
#define RFM12_LNA_GAIN RFM12_RXCTRL_LNA_6
#define RFM12_RSSI_THRESHOLD RFM12_RXCTRL_RSSI_79
#define RFM12_POWER RFM12_TXCONF_POWER_0
#define RFM12_FSK_SHIFT 125000

/* *********************************************************************** */

#define RFM12_DATA_STATE_FREE 0x00
#define RFM12_DATA_STATE_USED 0x01

struct rfm12_data
{
uint8_t state; /* RFM12_DATA_STATE_* */
struct rfm12_packet packet;
};

#define RFM12_CTX_STATE_INAVTIVE 0x00
#define RFM12_CTX_STATE_RX_IDLE 0x01
#define RFM12_CTX_STATE_RX_ACTIVE 0x02
#define RFM12_CTX_STATE_TX_ACTIVE 0x03

struct rfm12_context
{
uint8_t state; /* RFM12_CTX_STATE_* */
uint8_t ch_free_ticks; /* number of ticks channel is unused */
uint8_t own_address;

uint8_t rx_idx_in; /* pkt receiving */
uint8_t rx_idx_out; /* pkt given to app */
uint8_t rx_checksum; /* receive checksum */
uint8_t rx_data_idx; /* byte position inside rx[].packet */

uint8_t tx_data_idx; /* byte position inside tx.packet */

struct rfm12_data rx[2];
struct rfm12_data tx;
};

static struct rfm12_context rfm12_ctx;

/* *********************************************************************** */

static uint16_t rfm12_data(uint16_t txdata)
{
uint16_t retval;

RFM12_CS_ACTIVE();

SPDR = (txdata >> 8);
while (!(SPSR & (1<<SPIF)));
retval = (SPDR << 8);

SPDR = (txdata & 0xFF);
while (!(SPSR & (1<<SPIF)));
retval |= SPDR;

RFM12_CS_INACTIVE();

return retval;
} /* rfm12_data */


ISR(RFM12_INT_VECT)
{
uint16_t rfm12_status;
uint8_t rfm12_reset_fifo = 0;
uint8_t data;

/* disable interrupt */
RFM12_INT_OFF();

/* clear interrupt flag */
RFM12_INT_CLEAR();

/* read upper status byte (interrupt flags) */
rfm12_status = rfm12_data(RFM12_CMD_STATUS);

/* FIFO interrupt */
if (rfm12_status & RFM12_STATUS_FFIT)
{
switch (rfm12_ctx.state)
{
case RFM12_CTX_STATE_RX_IDLE:
data = rfm12_data(RFM12_CMD_READ);

/* check if buffer is free */
if (rfm12_ctx.rx[rfm12_ctx.rx_idx_in].state != RFM12_DATA_STATE_FREE)
{
rfm12_reset_fifo = 1;
break;
}

/* store first header byte */
rfm12_ctx.rx[rfm12_ctx.rx_idx_in].packet.sync[RFM12_PKT_SYNC_SIZE] = data;

/* store state */
rfm12_ctx.state = RFM12_CTX_STATE_RX_ACTIVE;
rfm12_ctx.rx_data_idx = 1;
rfm12_ctx.rx_checksum = data;
break;

case RFM12_CTX_STATE_RX_ACTIVE:
data = rfm12_data(RFM12_CMD_READ);

/* check buffer size */
if (rfm12_ctx.rx_data_idx >= (RFM12_PKT_HEADER_SIZE + RFM12_PKT_MAX_DATA_SIZE))
{
rfm12_reset_fifo = 1;
break;
}

/* store data */
(& rfm12_ctx.rx[rfm12_ctx.rx_idx_in].packet.sync[RFM12_PKT_SYNC_SIZE])[rfm12_ctx.rx_data_idx++] = data;

/* calculate checksum */
rfm12_ctx.rx_checksum ^= data;

/* check if header address, data_length and checksum are ok */
if ((rfm12_ctx.rx_data_idx == RFM12_PKT_HEADER_SIZE) &&
((rfm12_ctx.rx_checksum != 0xFF) ||
(rfm12_ctx.rx[rfm12_ctx.rx_idx_in].packet.dest_address != rfm12_ctx.own_address) ||
(rfm12_ctx.rx[rfm12_ctx.rx_idx_in].packet.source_address == rfm12_ctx.own_address) ||
(rfm12_ctx.rx[rfm12_ctx.rx_idx_in].packet.data_length > RFM12_PKT_MAX_DATA_SIZE)
))
{
rfm12_reset_fifo = 1;
break;
}

/* packet complete? */
if (rfm12_ctx.rx_data_idx == (RFM12_PKT_HEADER_SIZE + rfm12_ctx.rx[rfm12_ctx.rx_idx_in].packet.data_length))
{
/* mark buffer as full */
rfm12_ctx.rx[rfm12_ctx.rx_idx_in].state = RFM12_DATA_STATE_USED;

/* switch to other buffer */
rfm12_ctx.rx_idx_in ^= 1;

/* receiving is complete, reset fifo anyway */
rfm12_reset_fifo = 1;
}
break;

case RFM12_CTX_STATE_TX_ACTIVE:
/* send one additional byte! (<= not <) */
if (rfm12_ctx.tx_data_idx <= (RFM12_PKT_SYNC_SIZE + RFM12_PKT_HEADER_SIZE + rfm12_ctx.tx.packet.data_length))
{
rfm12_data(RFM12_CMD_TX | rfm12_ctx.tx.packet.sync[rfm12_ctx.tx_data_idx++]);
}
else
{
/* enable RX */
rfm12_data(RFM12_CMD_PWRMGT | RFM12_PWRMGT_ER | RFM12_PWRMGT_DC);

/* TX dummy byte to clear interrupt */
rfm12_data(RFM12_CMD_TX | RFM12_PREAMBLE);

/* mark buffer as empty */
rfm12_ctx.tx.state = RFM12_DATA_STATE_FREE;

/* transmit is complete, reset fifo */
rfm12_reset_fifo = 1;
}
break;

default:
rfm12_reset_fifo = 1;
break;
}

if (rfm12_reset_fifo)
{
/* flush fifo and wait for sync pattern */
rfm12_data(RFM12_CMD_FIFORESET | RFM12_FIFORESET_DR | (8<<4));
rfm12_data(RFM12_CMD_FIFORESET | RFM12_FIFORESET_DR | (8<<4) | RFM12_FIFORESET_FF);

/* wait for RX data */
rfm12_ctx.state = RFM12_CTX_STATE_RX_IDLE;
}
}

/* enable interrupt again */
RFM12_INT_ON();
} /* INT1_vect */


void rfm12_tick(uint8_t channel_free_time)
{
uint16_t status;

/* receiver not idle, come back later */
if (rfm12_ctx.state != RFM12_CTX_STATE_RX_IDLE)
{
return;
}

RFM12_INT_OFF();
status = rfm12_data(RFM12_CMD_STATUS);
RFM12_INT_ON();

/* check if module receives a carrier */
if (status & RFM12_STATUS_RSSI)
{
rfm12_ctx.ch_free_ticks = 0;
return;
}
else if (rfm12_ctx.ch_free_ticks <= channel_free_time)
{
rfm12_ctx.ch_free_ticks++;
return;
}

if (rfm12_ctx.tx.state == RFM12_DATA_STATE_USED)
{
RFM12_INT_OFF();

/* disable receiver */
rfm12_data(RFM12_CMD_PWRMGT | RFM12_PWRMGT_DC);

/* put preamble in fifo */
rfm12_data(RFM12_CMD_TX | RFM12_PREAMBLE);
rfm12_data(RFM12_CMD_TX | RFM12_PREAMBLE);

/* start TX */
rfm12_data(RFM12_CMD_PWRMGT | RFM12_PWRMGT_ET | RFM12_PWRMGT_DC);

/* change state */
rfm12_ctx.state = RFM12_CTX_STATE_TX_ACTIVE;
rfm12_ctx.tx_data_idx = 0;

RFM12_INT_ON();
}
} /* rfm12_tick */


static uint16_t rfm12_calc_crc(const struct rfm12_packet *pkt)
{
uint16_t crc = 0x0000;
uint8_t i;

const uint8_t *tmp = pkt->data;
for (i = 0; i < pkt->data_length; i++)
crc = _crc_ccitt_update(crc, *tmp++);

return crc;
} /* pkt_check_crc */


struct rfm12_packet * rfm12_get_txpkt(void)
{
if (rfm12_ctx.tx.state != RFM12_DATA_STATE_FREE)
{
return (void *)0;
}

return &rfm12_ctx.tx.packet;
} /* rfm12_get_txpkt */


uint8_t rfm12_start_tx(void)
{
struct rfm12_packet *pkt = &rfm12_ctx.tx.packet;

if ((rfm12_ctx.tx.state != RFM12_DATA_STATE_FREE) &&
(pkt->data_length > RFM12_PKT_MAX_DATA_SIZE)
)
{
return 0;
}

/* calculate data crc */
uint16_t *data_crc = (uint16_t *)(pkt->data + pkt->data_length);
*data_crc = rfm12_calc_crc(pkt);
pkt->data_length += 2;

/* setup packet */
pkt->sync[0] = RFM12_SYNC_MSB;
pkt->sync[1] = RFM12_SYNC_LSB;
pkt->source_address = rfm12_ctx.own_address;
pkt->header_checksum = pkt->dest_address ^ pkt->source_address ^ pkt->data_length ^ 0xFF;

/* change state */
rfm12_ctx.tx.state = RFM12_DATA_STATE_USED;

return 1;
} /* rfm12_start_tx */


struct rfm12_packet * rfm12_get_rxpkt(void)
{
if (rfm12_ctx.rx[rfm12_ctx.rx_idx_out].state != RFM12_DATA_STATE_USED)
{
return (void *)0;
}

/* calculate data crc */
struct rfm12_packet *pkt = &rfm12_ctx.rx[rfm12_ctx.rx_idx_out].packet;

pkt->data_length -= 2;

uint16_t *data_crc = (uint16_t *)(pkt->data + pkt->data_length);

if (*data_crc != rfm12_calc_crc(pkt))
{
rfm12_clear_rx();
return (void *)0;
}

return pkt;
} /* rfm12_get_rxpkt */


void rfm12_clear_rx(void)
{
/* mark buffer as empty */
rfm12_ctx.rx[rfm12_ctx.rx_idx_out].state = RFM12_DATA_STATE_FREE;

/* switch to other buffer */
rfm12_ctx.rx_idx_out ^= 1;
} /* rfm12_clear_rx */


static const uint16_t init_cmds[] PROGMEM =
{
/* set power default state (disable clock output) */
(RFM12_CMD_PWRMGT | RFM12_PWRMGT_DC),

/* dummy write after power management change, prevent lockup of module */
(RFM12_CMD_TX),

/* enable internal data register and fifo, setup selected band */
(RFM12_CMD_CFG | RFM12_CFG_EL | RFM12_CFG_EF | RFM12_BASEBAND | RFM12_XTAL_LOAD),

/* set frequency */
(RFM12_CMD_FREQUENCY | RFM12_FREQUENCY_CALC(RFM12_FREQUENCY)),

/* set data rate */
(RFM12_CMD_DATARATE | RFM12_DATARATE),

/* set rx parameters: vdi-out, bandwidth, LNA, RSSI */
(RFM12_CMD_RXCTRL | RFM12_RXCTRL_P16_VDI | RFM12_RXCTRL_VDI_FAST | RFM12_FILTER_BW | RFM12_LNA_GAIN | RFM12_RSSI_THRESHOLD),

/* automatic clock lock control, digital Filter,
* Data quality detector value 3, slow clock recovery lock
*/
(RFM12_CMD_DATAFILTER | RFM12_DATAFILTER_AL | 3),

/* 2 Byte Sync Pattern, Start fifo fill when sychron pattern received,
* disable sensitive reset, Fifo filled interrupt at 8 bits
*/
(RFM12_CMD_FIFORESET | RFM12_FIFORESET_DR | (8<<4)),

/* set AFC to automatic, (+4 or -3)*2.5kHz Limit, fine mode, active and enabled */
(RFM12_CMD_AFC | RFM12_AFC_AUTO_KEEP | RFM12_AFC_LIMIT_4 | RFM12_AFC_FI | RFM12_AFC_OE | RFM12_AFC_EN),

/* set TX Power, frequency shift */
(RFM12_CMD_TXCONF | RFM12_POWER | RFM12_TXCONF_FS_CALC(RFM12_FSK_SHIFT)),

/* disable low dutycycle mode */
(RFM12_CMD_DUTYCYCLE),

/* disable wakeup timer */
(RFM12_CMD_WAKEUP),

/* enable rf receiver chain */
(RFM12_CMD_PWRMGT | RFM12_PWRMGT_ER | RFM12_PWRMGT_DC),

/* flush fifo, start receiving */
(RFM12_CMD_FIFORESET | RFM12_FIFORESET_DR | (8<<4)),
(RFM12_CMD_FIFORESET | RFM12_FIFORESET_DR | (8<<4) | RFM12_FIFORESET_FF),
};


void rfm12_init(uint8_t own_address)
{
uint8_t i;

/* init chipselect GPIO */
RFM12_CS_INIT();
RFM12_CS_INACTIVE();

/* init internal SPI */
RFM12_SPI_INIT();

/* send init commands */
for (i = 0; i < ( sizeof(init_cmds) / 2) ; i++)
{
rfm12_data(pgm_read_word(&init_cmds[i]));
}

/* store own address */
rfm12_ctx.own_address = own_address;
rfm12_ctx.state = RFM12_CTX_STATE_RX_IDLE;

/* initalize & activate interrupt */
RFM12_INT_INIT();
RFM12_INT_CLEAR();
RFM12_INT_ON();
} /* rfm12_init */

+ 39
- 0
rfm12.h View File

@@ -0,0 +1,39 @@
#ifndef __RFM12_H__
#define __RFM12_H__

/* ************************************************************************ */

#define RFM12_PKT_SYNC_SIZE 2
#define RFM12_PKT_HEADER_SIZE 4
#define RFM12_PKT_MAX_DATA_SIZE 42

struct rfm12_packet
{
/* tx-only sync bytes */
uint8_t sync[RFM12_PKT_SYNC_SIZE];

/* Header */
uint8_t dest_address;
uint8_t source_address;
uint8_t data_length;
uint8_t header_checksum;

/* Data */
uint8_t data[RFM12_PKT_MAX_DATA_SIZE];
uint16_t data_crc;
};

/* ************************************************************************ */

void rfm12_init (uint8_t own_address);
void rfm12_tick (uint8_t channel_free_time);

struct rfm12_packet * rfm12_get_txpkt (void);
uint8_t rfm12_start_tx (void);

struct rfm12_packet * rfm12_get_rxpkt (void);
void rfm12_clear_rx (void);

/* ************************************************************************ */

#endif /* __RFM12_H__ */

+ 575
- 0
rfm12_hw.h View File

@@ -0,0 +1,575 @@
/**** RFM 12 library for Atmel AVR Microcontrollers *******
*
* This software is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation; either version 2 of the License,
* or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA.
*
* @author Peter Fuhrmann, Hans-Gert Dahmen, Soeren Heisrath
*/

/* Configuration setting command
Bit el enables the internal data register.
Bit ef enables the FIFO mode. If ef=0 then DATA (pin 6) and DCLK (pin 7) are used for data and data clock output.
x3 x2 x1 x0 Crystal Load Capacitance [pF]
0 0 0 0 8.5
0 0 0 1 9.0
0 0 1 0 9.5
0 0 1 1 10.0
....
1 1 1 0 15.5
1 1 1 1 16.0
*/
# define RFM12_CMD_CFG 0x8000
# define RFM12_CFG_EL 0x80
# define RFM12_CFG_EF 0x40
# define RFM12_CFG_BAND_MASK 0x30
# define RFM12_BAND_315 0x00
# define RFM12_BAND_433 0x10
# define RFM12_BAND_868 0x20
# define RFM12_BAND_915 0x30

# define RFM12_CFG_XTAL_MASK 0x0F
# define RFM12_XTAL_8_5PF 0x00
# define RFM12_XTAL_9_0PF 0x01
# define RFM12_XTAL_9_5PF 0x02
# define RFM12_XTAL_10_0PF 0x03
# define RFM12_XTAL_10_5PF 0x04
# define RFM12_XTAL_11_0PF 0x05
# define RFM12_XTAL_11_5PF 0x06
# define RFM12_XTAL_12_0PF 0x07
# define RFM12_XTAL_12_5PF 0x08
# define RFM12_XTAL_13_0PF 0x09
# define RFM12_XTAL_13_5PF 0x0A
# define RFM12_XTAL_14_0PF 0x0B
# define RFM12_XTAL_14_5PF 0x0C
# define RFM12_XTAL_15_0PF 0x0D
# define RFM12_XTAL_15_5PF 0x0E
# define RFM12_XTAL_16_0PF 0x0F


/*
2. Power Management Command
Bit Function of the control bit Related blocks
er Enables the whole receiver chain RF front end, baseband, synthesizer, oscillator
ebb The receiver baseband circuit can be separately switched on Baseband
et Switches on the PLL, the power amplifier, and starts the
transmission (If TX register is enabled) Power amplifier, synthesizer, oscillator
es Turns on the synthesizer Synthesizer
ex Turns on the crystal oscillator Crystal oscillator
eb Enables the low battery detector Low battery detector
ew Enables the wake-up timer Wake-up timer
dc Disables the clock output (pin 8) Clock output buffer
*/
#define RFM12_CMD_PWRMGT 0x8200
#define RFM12_PWRMGT_ER 0x80
#define RFM12_PWRMGT_EBB 0x40
#define RFM12_PWRMGT_ET 0x20
#define RFM12_PWRMGT_ES 0x10
#define RFM12_PWRMGT_EX 0x08
#define RFM12_PWRMGT_EB 0x04
#define RFM12_PWRMGT_EW 0x02
#define RFM12_PWRMGT_DC 0x01

/*
3. Frequency Setting Command
Bit 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 POR
1 0 1 0 f11 f10 f9 f8 f7 f6 f5 f4 f3 f2 f1 f0 A680h
The 12-bit parameter F (bits f11 to f0) should be in the range
of 96 and 3903. When F value sent is out of range, the
previous value is kept. The synthesizer center frequency f0 can
be calculated as:
f0 = 10 * C1 * (C2 + F/4000) [MHz]
The constants C1 and C2 are determined by
the selected band as:
Band [MHz] C1 C2
433 1 43
868 2 43
915 3 30

Frequency in 433 Band can be from 430.24MHz to 439.7575MHz in 2.5kHz increments.
*/

#define RFM12_CMD_FREQUENCY 0xA000
#define RFM12_FREQUENCY_MASK 0x0FFF
#define RFM12_FREQUENCY_CALC_433(f) (((f)-430000000UL)/2500UL)
#define RFM12_FREQUENCY_CALC_868(f) (((f)-860000000UL)/5000UL)
#define RFM12_FREQUENCY_CALC_915(f) (((f)-900000000UL)/7500UL)


/*
4. Data Rate Command
Bit 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 POR
1 1 0 0 0 1 1 0 cs r6 r5 r4 r3 r2 r1 r0 C623h
The actual bit rate in transmit mode and the expected bit rate of the received data stream in receive mode is determined by the 7-bit
parameter R (bits r6 to r0) and bit cs.
BR = 10000 / 29 / (R+1) / (1+cs*7) [kbps]
In the receiver set R according to the next function:
R = (10000 / 29 / (1+cs*7) / BR) – 1, where BR is the expected bit rate in kbps.
Apart from setting custom values, the standard bit rates from 600 bps to 115.2 kbps can be approximated with small error.
Data rate accuracy requirements:
Clock recovery in slow mode: ΔBR/BR < 1/(29*Nbit) Clock recovery in fast mode: ΔBR/BR < 3/(29*Nbit)
BR is the bit rate set in the receiver and ΔBR is the bit rate difference between the transmitter and the receiver. Nbit is the maximum
number of consecutive ones or zeros in the data stream. It is recommended for long data packets to include enough 1/0 and 0/1
transitions, and to be careful to use the same division ratio in the receiver and in the transmitter.
*/

#define RFM12_CMD_DATARATE 0xC600
#define RFM12_DATARATE_CS 0x80
//calculate setting for datarates >= 2700 Baud
#define RFM12_DATARATE_CALC_HIGH(d) ((uint8_t)((10000000.0/29.0/d)-0.5))
//calculate setting for datarates < 2700 Baud
#define RFM12_DATARATE_CALC_LOW(d) (RFM12_DATARATE_CS|(uint8_t)((10000000.0/29.0/8.0/d)-0.5))
#define RFM12_DATARATE_MASK 0x00ff

/*
5. Receiver Control Command
Bit 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 POR
1 0 0 1 0 p16 d1 d0 i2 i1 i0 g1 g0 r2 r1 r0 9080h
Bit 10 (p16): pin16 function select

p16 Function of pin 16
0 Interrupt input
1 VDI output

Bits 9-8 (d1 to d0): VDI (valid data indicator) signal response time setting:
d1 d0 Response
0 0 Fast
0 1 Medium
1 0 Slow
1 1 Always on

Bits 7-5 (i2 to i0): Receiver baseband bandwidth (BW) select:
i2 i1 i0 BW [kHz]
0 0 0 reserved
0 0 1 400
0 1 0 340
0 1 1 270
1 0 0 200
1 0 1 134
1 1 0 67
1 1 1 reserved
Bits 4-3 (g1 to g0): LNA gain select:
g1 g0 relative to maximum [dB]
0 0 0
0 1 -6
1 0 -14
1 1 -20

Bits 2-0 (r2 to r0): RSSI detector threshold:
r2 r1 r0 RSSIsetth [dBm]
0 0 0 -103
0 0 1 -97
0 1 0 -91
0 1 1 -85
1 0 0 -79
1 0 1 -73
1 1 0 Reserved
1 1 1 Reserved
The RSSI threshold depends on the LNA gain, the real RSSI threshold can be calculated:
RSSIth=RSSIsetth+GLNA

*/

#define RFM12_CMD_RXCTRL 0x9000
#define RFM12_RXCTRL_P16_VDI 0x400
#define RFM12_RXCTRL_VDI_FAST 0x000
#define RFM12_RXCTRL_VDI_MEDIUM 0x100
#define RFM12_RXCTRL_VDI_SLOW 0x200
#define RFM12_RXCTRL_VDI_ALWAYS_ON 0x300

#define RFM12_RXCTRL_BW_MASK 0xE0
#define RFM12_RXCTRL_BW_400 0x20
#define RFM12_RXCTRL_BW_340 0x40
#define RFM12_RXCTRL_BW_270 0x60
#define RFM12_RXCTRL_BW_200 0x80
#define RFM12_RXCTRL_BW_134 0xA0
#define RFM12_RXCTRL_BW_67 0xC0

#define RFM12_RXCTRL_LNA_MASK 0x18
#define RFM12_RXCTRL_LNA_0 0x00
#define RFM12_RXCTRL_LNA_6 0x08
#define RFM12_RXCTRL_LNA_14 0x10
#define RFM12_RXCTRL_LNA_20 0x18

#define RFM12_RXCTRL_RSSI_103 0x00
#define RFM12_RXCTRL_RSSI_97 0x01
#define RFM12_RXCTRL_RSSI_91 0x02
#define RFM12_RXCTRL_RSSI_85 0x03
#define RFM12_RXCTRL_RSSI_79 0x04
#define RFM12_RXCTRL_RSSI_73 0x05
#define RFM12_RXCTRL_RSSI_67 0x06
#define RFM12_RXCTRL_RSSI_61 0x07
#define RFM12_RXCTRL_RSSI_MASK 0x07



/*
6. Data Filter Command
Bit 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 POR
1 1 0 0 0 0 1 0 al ml 1 s 1 f2 f1 f0 C22Ch

Bit 7 (al): Clock recovery (CR) auto lock control, if set.
CR will start in fast mode, then after locking it will automatically switch to slow mode.

Bit 6 (ml): Clock recovery lock control
1: fast mode, fast attack and fast release (4 to 8 bit preamble (1010...) is recommended)
0: slow mode, slow attack and slow release (12 to 16 bit preamble is recommended)
Using the slow mode requires more accurate bit timing (see Data Rate Command).

Bits 4 (s): Select the type of the data filter:
s Filter Type
0 Digital filter
1 Analog RC filter
Digital: This is a digital realization of an analog RC filter followed by a comparator with hysteresis. The time constant is
automatically adjusted to the bit rate defined by the Data Rate Command.
Note: Bit rate can not exceed 115 kpbs in this mode.
Analog RC filter: The demodulator output is fed to pin 7 over a 10 kOhm resistor. The filter cut-off frequency is set by the
external capacitor connected to this pin and VSS.

Bits 2-0 (f2 to f0): DQD threshold parameter.
Note: To let the DQD report "good signal quality" the threshold parameter should be 4 in cases where the bitrate is close to the
deviation. At higher deviation/bitrate settings, a higher threshold parameter can report "good signal quality" as well.
*/

#define RFM12_CMD_DATAFILTER 0xC228
#define RFM12_DATAFILTER_AL 0x80
#define RFM12_DATAFILTER_ML 0x40
#define RFM12_DATAFILTER_S 0x10


/*
7. FIFO and Reset Mode Command
Bit 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 POR
1 1 0 0 1 0 1 0 f3 f2 f1 f0 sp al ff dr CA80h

Bits 7-4 (f3 to f0): FIFO IT level. The FIFO generates IT when the number of received data bits reaches this level.

Bit 3 (sp): Select the length of the synchron pattern:
sp Byte1 Byte0 (POR) Synchron Pattern (Byte1+Byte0)
0 2Dh D4h 2DD4h
1 Not used D4h D4h
Note: Byte0 can be programmed by the Synchron Pattern Command.

Bit 2 (al): Set the input of the FIFO fill start condition:
al
0 Synchron pattern
1 Always fill

Bit 1 (ff): FIFO fill will be enabled after synchron pattern reception. The FIFO fill stops when this bit is cleared.
Bit 0 (dr): Disables the highly sensitive RESET mode.

*/
#define RFM12_CMD_FIFORESET 0xCA00
#define RFM12_FIFORESET_SP 0x08
#define RFM12_FIFORESET_AL 0x04
#define RFM12_FIFORESET_FF 0x02
#define RFM12_FIFORESET_DR 0x01

/*
8. Synchron Pattern Command
Bit 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 POR
1 1 0 0 1 1 1 0 b7 b6 b5 b4 b3 b2 b1 b0 CED4h
The Byte0 used for synchron pattern detection can be reprogrammed by B <b7:b0>.
*/
#define RFM12_CMD_SYNCPATTERN 0xCE00

/*
9. Receiver FIFO Read Command
Bit 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 POR
1 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 B000h
With this command, the controller can read 8 bits from the receiver FIFO. Bit 6 (ef) must be set in Configuration Setting Command.

Note:: During FIFO access fSCK cannot be higher than fref /4, where fref is the crystal oscillator frequency. When the duty-cycle of the
clock signal is not 50 % the shorter period of the clock pulse width should be at least 2/fref .
*/

#define RFM12_CMD_READ 0xB000

/*
10. AFC Command
Bit 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 POR
1 1 0 0 0 1 0 0 a1 a0 rl1 rl0 st fi oe en C4F7h

Bit 7-6 (a1 to a0): Automatic operation mode selector:
a1 a0
0 0 Auto mode off (Strobe is controlled by microcontroller)
0 1 Runs only once after each power-up
1 0 Keep the foffset only during receiving (VDI=high)
1 1 Keep the foffset value independently from the state of the VDI signal

Bit 5-4 (rl1 to rl0): Range limit. Limits the value of the frequency offset register to the next values:
rl1 rl0 Max deviation
0 0 No restriction (+63 fres to -64 fres)
0 1 +15 fres to -16 fres
1 0 +7 fres to -8 fres
1 1 +3 fres to -4 fres
fres:
433 MHz bands: 2.5 kHz
868 MHz band: 5 kHz
915 MHz band: 7.5 kHz

Bit 3 (st): Strobe edge, when st goes to high, the actual latest calculated frequency error is stored into the offset register of the AFC
block.
Bit 2 (fi): Switches the circuit to high accuracy (fine) mode. In this case, the processing time is about twice as long, but the measurement
uncertainty is about half.
Bit 1 (oe): Enables the frequency offset register. It allows the addition of the offset register to the frequency control word of the PLL.
Bit 0 (en): Enables the calculation of the offset frequency by the AFC circuit.

In automatic operation mode (no strobe signal is needed from the microcontroller to update the output offset register) the AFC circuit
is automatically enabled when the VDI indicates potential incoming signal during the whole measurement cycle and the circuit
measures the same result in two subsequent cycles.
There are three operation modes, examples from the possible application:
1, (a1=0, a0=1) The circuit measures the frequency offset only once after power up. This way, extended TX-RX maximum distance
can be achieved.
Possible application:
In the final application, when the user inserts the battery, the circuit measures and compensates for the frequency offset caused by
the crystal tolerances. This method allows for the use of a cheaper quartz in the application and provides protection against tracking
an interferer.
2a, (a1=1, a0=0) The circuit automatically measures the frequency offset during an initial effective low data rate pattern –easier to
receive- (i.e.: 00110011) of the package and changes the receiving frequency accordingly. The further part of the package can be
received by the corrected frequency settings.
2b, (a1=1, a0=0) The transmitter must transmit the first part of the packet with a step higher deviation and later there is a possibility
of reducing it.
In both cases (2a and 2b), when the VDI indicates poor receiving conditions (VDI goes low), the output register is automatically
cleared. Use these settings when receiving signals from different transmitters transmitting in the same nominal frequencies.
3, (a1=1, a0=1) It’s the same as 2a and 2b modes, but suggested to use when a receiver operates with only one transmitter. After a
complete measuring cycle, the measured value is kept independently of the state of the VDI signal.
*/

#define RFM12_CMD_AFC 0xC400
#define RFM12_AFC_AUTO_OFF 0x00
#define RFM12_AFC_AUTO_ONCE 0x40
#define RFM12_AFC_AUTO_VDI 0x80
#define RFM12_AFC_AUTO_KEEP 0xC0
#define RFM12_AFC_LIMIT_OFF 0x00 /* 64 */
#define RFM12_AFC_LIMIT_16 0x10
#define RFM12_AFC_LIMIT_8 0x20
#define RFM12_AFC_LIMIT_4 0x30
#define RFM12_AFC_ST 0x08
#define RFM12_AFC_FI 0x04
#define RFM12_AFC_OE 0x02
#define RFM12_AFC_EN 0x01

/*
11. TX Configuration Control Command
Bit 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 POR
1 0 0 1 1 0 0 mp m3 m2 m1 m0 0 p2 p1 p0 9800h

Bits 8-4 (mp, m3 to m0): FSK modulation parameters:
The resulting output frequency can be calculated as:
fout = f0 + (-1)SIGN * (M + 1) * (15 kHz)
where:
f0 is the channel center frequency (see the
Frequency Setting Command)
M is the four bit binary number <m3 : m0>
SIGN = (mp) XOR FSK

Bits 2-0 (p2 to p0): Output power:
p2 p1 p0 Relative Output Power [dB]
0 0 0 0
0 0 1 -2.5
0 1 0 -5
0 1 1 -7.5
1 0 0 -10
1 0 1 -12.5
1 1 0 -15
1 1 1 -17.5

*/

#define RFM12_CMD_TXCONF 0x9800
#define RFM12_TXCONF_MP 0x100
#define RFM12_TXCONF_POWER_0 0x00
#define RFM12_TXCONF_POWER_3 0x01
#define RFM12_TXCONF_POWER_6 0x02
#define RFM12_TXCONF_POWER_9 0x03
#define RFM12_TXCONF_POWER_12 0x04
#define RFM12_TXCONF_POWER_15 0x05
#define RFM12_TXCONF_POWER_18 0x06
#define RFM12_TXCONF_POWER_21 0x07
#define RFM12_TXCONF_FSK_MASK 0xf0
#define RFM12_TXCONF_FS_CALC(f) (((f/15000UL)-1)<<4)
#define RFM12_TXCONF_MASK 0x01F7
#define RFM12_TXCONF_POWER_MASK 0x07



/*
12. PLL Setting Command
Bit 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 POR
1 1 0 0 1 1 0 0 0 ob1 ob0 0 ddy ddit 1 bw0 CC67h
Note: POR default setting of the register carefully selected to cover almost all typical applications.
Bit 6-5 (ob1-ob0): Microcontroller output clock buffer rise and fall time control.
ob1 ob0 Selected uC CLK frequency
0 0 5 or 10 MHz (recommended)
0 1 3.3 MHz
1 X 2.5 MHz or less

(Typ conditions: Top = 27 oC; Vdd = Voc = 2.7 V, Crystal ESR = 30 Ohm)

Bit 3 (ddy): Switches on the delay in the phase detector when this bit is set.
Bit 2 (ddit): When set, disables the dithering in the PLL loop.
Bit 0 (bw0): PLL bandwidth can be set for optimal TX RF performance.

bw0 Max bit rate [kbps] Phase noise at 1MHz offset [dBc/Hz]
0 86.2 -107
1 256 -102

Note: Needed for optimization of the RF
performance. Optimal settings can vary
according to the external load capacitance.
*/

#define RFM12_CMD_PLL 0xCC02
#define RFM12_PLL_DDY 0x08
#define RFM12_PLL_DDIT 0x04
#define RFM12_PLL_BW0 0x01

/*
13. Transmitter Register Write Command
Bit 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 POR
1 0 1 1 1 0 0 0 t7 t6 t5 t4 t3 t2 t1 t0 B8AAh
With this command, the controller can write 8 bits (t7 to t0) to the transmitter data register. Bit 7 (el) must be set in Configuration
Setting Command.
*/

#define RFM12_CMD_TX 0xB800

/*
14. Wake-Up Timer Command
Bit 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 POR
1 1 1 r4 r3 r2 r1 r0 m7 m6 m5 m4 m3 m2 m1 m0 E196h
The wake-up time period can be calculated by (m7 to m0) and (r4 to r0):
Twake-up = 1.03 * M * 2R + 0.5 [ms]
Note:
• For continual operation the ew bit should be cleared and set at the end of every cycle.
• For future compatibility, use R in a range of 0 and 29.
*/
#define RFM12_CMD_WAKEUP 0xE000


/*
15. Low Duty-Cycle Command
Bit 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 POR
1 1 0 0 1 0 0 0 d6 d5 d4 d3 d2 d1 d0 en C80Eh
With this command, Low Duty-Cycle operation can be set in order to decrease the average power consumption in receiver mode.
The time cycle is determined by the Wake-Up Timer Command.
The Duty-Cycle can be calculated by using (d6 to d0) and M. (M is parameter in a Wake-Up Timer Command.)
Duty-Cycle= (D * 2 +1) / M *100%
The on-cycle is automatically extended while DQD indicates good received signal condition (FSK transmission is detected in the
frequency range determined by Frequency Setting Command plus and minus the baseband filter bandwidth determined by the
Receiver Control Command).
*/
#define RFM12_CMD_DUTYCYCLE 0xC800
#define RFM12_DUTYCYCLE_ENABLE 0x01

/*
16. Low Battery Detector and Microcontroller Clock Divider Command
Bit 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 POR
1 1 0 0 0 0 0 0 d2 d1 d0 0 v3 v2 v1 v0 C000h
The 4 bit parameter (v3 to v0) represents the value V, which defines the threshold voltage Vlb of the detector:
Vlb= 2.25 + V * 0.1 [V]
Clock divider configuration:
Clock Output
Frequency [MHz]
0 0 0 1
0 0 1 1.25
0 1 0 1.66
0 1 1 2
1 0 0 2.5
1 0 1 3.33
1 1 0 5
1 1 1 10
d2 d1 d0
The low battery detector and the clock output can be enabled or disabled by bits eb and dc, respectively, using the Power
Management Command.
*/
#define RFM12_CMD_LBDMCD 0xC000

#define RFM12_LBD_VOLTAGE_2V2 0
#define RFM12_LBD_VOLTAGE_2V3 1
#define RFM12_LBD_VOLTAGE_2V4 2
#define RFM12_LBD_VOLTAGE_2V5 3
#define RFM12_LBD_VOLTAGE_2V6 4
#define RFM12_LBD_VOLTAGE_2V7 5
#define RFM12_LBD_VOLTAGE_2V8 6
#define RFM12_LBD_VOLTAGE_2V9 7
#define RFM12_LBD_VOLTAGE_3V0 8
#define RFM12_LBD_VOLTAGE_3V1 9
#define RFM12_LBD_VOLTAGE_3V2 10
#define RFM12_LBD_VOLTAGE_3V3 11
#define RFM12_LBD_VOLTAGE_3V4 12
#define RFM12_LBD_VOLTAGE_3V5 13
#define RFM12_LBD_VOLTAGE_3V6 14
#define RFM12_LBD_VOLTAGE_3V7 15

#define RFM12_CLOCK_OUT_FREQUENCY_1_00_MHz (0<<5)
#define RFM12_CLOCK_OUT_FREQUENCY_1_25_MHz (1<<5)
#define RFM12_CLOCK_OUT_FREQUENCY_1_66_MHz (2<<5)
#define RFM12_CLOCK_OUT_FREQUENCY_2_00_MHz (3<<5)
#define RFM12_CLOCK_OUT_FREQUENCY_2_50_MHz (4<<5)
#define RFM12_CLOCK_OUT_FREQUENCY_3_33_MHz (5<<5)
#define RFM12_CLOCK_OUT_FREQUENCY_5_00_MHz (6<<5)
#define RFM12_CLOCK_OUT_FREQUENCY_10_00_MHz (7<<5)



/*
17. Status Read Command
The read command starts with a zero, whereas all other control commands start with a one. If a read command is identified, the
status bits will be clocked out on the SDO pin as follows:

bitnumber
15 RGIT TX register is ready to receive the next byte (Can be cleared by Transmitter Register Write Command)
FFIT The number of data bits in the RX FIFO has reached the pre-programmed limit (Can be cleared by any of the
FIFO read methods)
14 POR Power-on reset (Cleared after Status Read Command)
13 RGUR TX register under run, register over write (Cleared after Status Read Command)
FFOV RX FIFO overflow (Cleared after Status Read Command)
12 WKUP Wake-up timer overflow (Cleared after Status Read Command)
11 EXT Logic level on interrupt pin (pin 16) changed to low (Cleared after Status Read Command)
10 LBD Low battery detect, the power supply voltage is below the pre-programmed limit
9 FFEM FIFO is empty
8 ATS Antenna tuning circuit detected strong enough RF signal
RSSI The strength of the incoming signal is above the pre-programmed limit
7 DQD Data quality detector output
6 CRL Clock recovery locked
5 ATGL Toggling in each AFC cycle
4 OFFS(6) MSB of the measured frequency offset (sign of the offset value)
3 OFFS(3) -OFFS(0) Offset value to be added to the value of the frequency control parameter (Four LSB bits)
2
1
0
*/

#define RFM12_CMD_STATUS 0x0000
#define RFM12_STATUS_RGIT 0x8000
#define RFM12_STATUS_FFIT 0x8000
#define RFM12_STATUS_POR 0x4000
#define RFM12_STATUS_RGUR 0x2000
#define RFM12_STATUS_FFOV 0x2000
#define RFM12_STATUS_WKUP 0x1000
#define RFM12_STATUS_EXT 0x0800
#define RFM12_STATUS_LBD 0x0400
#define RFM12_STATUS_FFEM 0x0200
#define RFM12_STATUS_ATS 0x0100
#define RFM12_STATUS_RSSI 0x0100
#define RFM12_STATUS_DQD 0x0080
#define RFM12_STATUS_CRL 0x0040
#define RFM12_STATUS_ATGL 0x0020


/* undocumented software reset command for the rf12
*/
#define RFM12_RESET 0xffff

+ 53
- 0
target.h View File

@@ -0,0 +1,53 @@
#ifndef __TARGET_H__
#define __TARGET_H__

/* *********************************************************************** */
#if defined(CONFIG_funkstuff168)
/*
* using ATmega168 @16MHz:
* Fuse E: 0xFA (512 words bootloader)
* Fuse H: 0xDD (2.7V BOD)
* Fuse L: 0xFF (external crystal)
*/
#define F_CPU 16000000
#define RFM12_ADDRESS 0x11
#define TIMEOUT 1000

/* 1ms @16MHz */
#define TIMER_RELOAD (0xFF - 250)

#define VERSION_STRING "FUNKBOOTm168v1.0"
#define SIGNATURE_BYTES 0x1E, 0x94, 0x06

#define LED_INIT() { DDRD |= ((1<<PORTD5) | (1<<PORTD6)); LED_OFF(); }
#define LED_GN_ON() PORTD &= ~(1<<PORTD5)
#define LED_GN_OFF() PORTD |= (1<<PORTD5)
#define LED_GN_TOGGLE() PORTD ^= (1<<PORTD5)
#define LED_RT_ON() PORTD &= ~(1<<PORTD6)
#define LED_RT_OFF() PORTD |= (1<<PORTD6)
#define LED_OFF() PORTD |= ((1<<PORTD5) | (1<<PORTD6))


#define RFM12_INT_INIT() EICRA |= (1<<ISC11)
#define RFM12_INT_ON() EIMSK |= (1<<INT1)
#define RFM12_INT_OFF() EIMSK &= ~(1<<INT1)
#define RFM12_INT_CLEAR() EIFR = INTF1
#define RFM12_INT_VECT INT1_vect

#define RFM12_CS_INIT() DDRD |= (1<<PORTD7)
#define RFM12_CS_ACTIVE() PORTD &= ~(1<<PORTD7)
#define RFM12_CS_INACTIVE() PORTD |= (1<<PORTD7)

#define RFM12_SPI_INIT() { /* SS, SCK and MOSI are outputs */ \
DDRB |= (1<<PORTB2) | (1<<PORTB3) | (1<<PORTB5); \
/* SPI Master, F_CPU /16 */ \
SPCR = (1<<SPE) | (1<<MSTR) | (1<<SPR0); \
}

/* *********************************************************************** */
#else
#error "unknown CONFIG"
#endif
/* *********************************************************************** */

#endif /* __TARGET_H__ */

Loading…
Cancel
Save