From 03c3b8f43a77b06894083e474fbd7560fe776211 Mon Sep 17 00:00:00 2001 From: fvantienen Date: Tue, 2 Jul 2013 16:40:40 +0200 Subject: [PATCH] [superbitrf] Initial commit for superbitrf 2.4GHz radio control --- .../quadrotor_lisa_m_2_pwm_spektrum.xml | 4 +- .../shared/radio_control_superbitrf.makefile | 14 + conf/messages.xml | 7 +- conf/telemetry/default_rotorcraft.xml | 1 + sw/airborne/firmwares/rotorcraft/telemetry.h | 12 + sw/airborne/mcu_periph/gpio.h | 4 + sw/airborne/peripherals/cyrf6936.c | 359 ++++++++++++++++++ sw/airborne/peripherals/cyrf6936.h | 70 ++++ sw/airborne/peripherals/cyrf6936_regs.h | 211 ++++++++++ .../subsystems/radio_control/superbitrf.c | 129 +++++++ .../subsystems/radio_control/superbitrf.h | 86 +++++ 11 files changed, 892 insertions(+), 5 deletions(-) create mode 100644 conf/firmwares/subsystems/shared/radio_control_superbitrf.makefile create mode 100644 sw/airborne/peripherals/cyrf6936.c create mode 100644 sw/airborne/peripherals/cyrf6936.h create mode 100644 sw/airborne/peripherals/cyrf6936_regs.h create mode 100644 sw/airborne/subsystems/radio_control/superbitrf.c create mode 100644 sw/airborne/subsystems/radio_control/superbitrf.h diff --git a/conf/airframes/examples/quadrotor_lisa_m_2_pwm_spektrum.xml b/conf/airframes/examples/quadrotor_lisa_m_2_pwm_spektrum.xml index 8881af6298..3244ea3474 100644 --- a/conf/airframes/examples/quadrotor_lisa_m_2_pwm_spektrum.xml +++ b/conf/airframes/examples/quadrotor_lisa_m_2_pwm_spektrum.xml @@ -12,9 +12,7 @@ - - - + diff --git a/conf/firmwares/subsystems/shared/radio_control_superbitrf.makefile b/conf/firmwares/subsystems/shared/radio_control_superbitrf.makefile new file mode 100644 index 0000000000..791751efde --- /dev/null +++ b/conf/firmwares/subsystems/shared/radio_control_superbitrf.makefile @@ -0,0 +1,14 @@ +# +# Makefile for shared radio_control superbitrf subsystem +# + +ap.CFLAGS += -DRADIO_CONTROL -DRADIO_CONTROL_TYPE_SUPERBITRF -DRADIO_CONTROL_TYPE_H=\"subsystems/radio_control/superbitrf.h\" +ap.CFLAGS += -DUSE_SPI1 -DUSE_SPI_SLAVE1 + +ifneq ($(RADIO_CONTROL_LED),none) +ap.CFLAGS += -DRADIO_CONTROL_LED=$(RADIO_CONTROL_LED) +endif + +ap.srcs += peripherals/cyrf6936.c \ + $(SRC_SUBSYSTEMS)/radio_control.c \ + $(SRC_SUBSYSTEMS)/radio_control/superbitrf.c diff --git a/conf/messages.xml b/conf/messages.xml index 3c5a9b2a29..2999fcab52 100644 --- a/conf/messages.xml +++ b/conf/messages.xml @@ -603,8 +603,11 @@ - - + + + + + diff --git a/conf/telemetry/default_rotorcraft.xml b/conf/telemetry/default_rotorcraft.xml index 6f83d9b340..0ed6ab52ae 100644 --- a/conf/telemetry/default_rotorcraft.xml +++ b/conf/telemetry/default_rotorcraft.xml @@ -26,6 +26,7 @@ + diff --git a/sw/airborne/firmwares/rotorcraft/telemetry.h b/sw/airborne/firmwares/rotorcraft/telemetry.h index a1b3472812..e08247b3f6 100644 --- a/sw/airborne/firmwares/rotorcraft/telemetry.h +++ b/sw/airborne/firmwares/rotorcraft/telemetry.h @@ -134,6 +134,18 @@ #define PERIODIC_SEND_PPM(_trans, _dev) {} #endif +#ifdef RADIO_CONTROL_TYPE_SUPERBITRF +#include "subsystems/radio_control/superbitrf.h" +#define PERIODIC_SEND_SUPERBITRF(_trans, _dev) { \ + DOWNLINK_SEND_SUPERBITRF(_trans, _dev, \ + &superbitrf.status, \ + &superbitrf.cyrf6936.status, \ + 6, \ + superbitrf.cyrf6936.mfg_id);} +#else +#define PERIODIC_SEND_SUPERBITRF(_trans, _dev) {} +#endif + #ifdef ACTUATORS #define PERIODIC_SEND_ACTUATORS(_trans, _dev) DOWNLINK_SEND_ACTUATORS(_trans, _dev, ACTUATORS_NB, actuators) #else diff --git a/sw/airborne/mcu_periph/gpio.h b/sw/airborne/mcu_periph/gpio.h index 1218ae6c05..0c500b3dd6 100644 --- a/sw/airborne/mcu_periph/gpio.h +++ b/sw/airborne/mcu_periph/gpio.h @@ -25,6 +25,9 @@ * Some architecture independent helper functions for GPIOs. */ +#ifndef MCU_PERIPH_GPIO_H +#define MCU_PERIPH_GPIO_H + #include "std.h" #include "mcu_periph/gpio_arch.h" @@ -38,3 +41,4 @@ extern void gpio_setup_output(uint32_t port, uint16_t pin); */ extern void gpio_setup_input(uint32_t port, uint16_t pin); +#endif /* MCU_PERIPH_GPIO_H */ diff --git a/sw/airborne/peripherals/cyrf6936.c b/sw/airborne/peripherals/cyrf6936.c new file mode 100644 index 0000000000..9613d4c095 --- /dev/null +++ b/sw/airborne/peripherals/cyrf6936.c @@ -0,0 +1,359 @@ +/* + * Copyright (C) 2013 Freek van Tienen + * + * This file is part of paparazzi. + * + * paparazzi 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, or (at your option) + * any later version. + * + * paparazzi 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 paparazzi; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/** + * @file peripherals/cyrf6936.c + * Driver for the cyrf6936 2.4GHz radio chip + */ + +#include "cyrf6936.h" +#include "mcu_periph/spi.h" +#include "mcu_periph/gpio.h" +#include "mcu_periph/gpio_arch.h" +#include "subsystems/radio_control.h" + +#include "mcu_periph/uart.h" +#include "messages.h" +#include "subsystems/datalink/downlink.h" + +/* Static functions used in the different statuses */ +static bool_t cyrf6936_write_register(struct Cyrf6936 *cyrf, const uint8_t addr, const uint8_t data); +static bool_t cyrf6936_write_block(struct Cyrf6936 *cyrf, const uint8_t addr, const uint8_t data[], const uint8_t length); +static bool_t cyrf6936_read_register(struct Cyrf6936 *cyrf, const uint8_t addr); +static bool_t cyrf6936_read_block(struct Cyrf6936 *cyrf, const uint8_t addr, const uint8_t length); + +//FIXME +void Delay(uint32_t x); +void Delay(uint32_t x) +{ + (void)x; + __asm ("mov r1, #24;" + "mul r0, r0, r1;" + "b _delaycmp;" + "_delayloop:" + "subs r0, r0, #1;" + "_delaycmp:;" + "cmp r0, #0;" + " bne _delayloop;"); +} + +/** + * Initializing the cyrf chip + */ +void cyrf6936_init(struct Cyrf6936 *cyrf, struct spi_periph *spi_p, const uint8_t slave_idx, const uint32_t rst_port, const uint16_t rst_pin) { + /* Set spi_peripheral and the status */ + cyrf->spi_p = spi_p; + cyrf->status = CYRF6936_UNINIT; + + /* Set the spi transaction */ + cyrf->spi_t.cpol = SPICpolIdleLow; + cyrf->spi_t.cpha = SPICphaEdge1; + cyrf->spi_t.dss = SPIDss8bit; + cyrf->spi_t.bitorder = SPIMSBFirst; + cyrf->spi_t.cdiv = SPIDiv64; + + cyrf->spi_t.input_length = 0; + cyrf->spi_t.output_length = 0; + cyrf->spi_t.input_buf = cyrf->input_buf; + cyrf->spi_t.output_buf = cyrf->output_buf; + cyrf->spi_t.slave_idx = slave_idx; + cyrf->spi_t.select = SPISelectUnselect; + cyrf->spi_t.status = SPITransDone; + + /* Reset the CYRF6936 chip */ + gpio_setup_output(rst_port, rst_pin); + gpio_output_high(rst_port, rst_pin); + Delay(100); + gpio_output_low(rst_port, rst_pin); + Delay(100); + + /* Get the MFG ID */ + cyrf->status = CYRF6936_GET_MFG_ID; + cyrf->buffer_idx = 0; + cyrf6936_write_register(cyrf, CYRF_MFG_ID, 0xFF); +} + +/** + * The on event call for the CYRF6936 chip + */ +void cyrf6936_event(struct Cyrf6936 *cyrf) { + int i; + // Check if cyrf is initialized + if(cyrf->status == CYRF6936_UNINIT) + return; + + // Check if there is still a transaction in progress + if(cyrf->spi_t.status == SPITransPending || cyrf->spi_t.status == SPITransRunning) + return; + + /* Check the status of the cyrf */ + switch (cyrf->status) { + + /* Getting the MFG id */ + case CYRF6936_GET_MFG_ID: + // When the last transaction isn't failed send the next + if(cyrf->spi_t.status != SPITransFailed) + cyrf->buffer_idx++; + + cyrf->spi_t.status = SPITransDone; + + // Switch for the different states + switch (cyrf->buffer_idx) { + case 0: + cyrf6936_write_register(cyrf, CYRF_MFG_ID, 0xFF); + break; + case 1: + cyrf6936_read_block(cyrf, CYRF_MFG_ID, 6); + break; + case 2: + // Copy the MFG id + for(i = 0; i < 6; i++) + cyrf->mfg_id[i] = cyrf->input_buf[i+1]; + + cyrf6936_write_register(cyrf, CYRF_MFG_ID, 0x00); + break; + default: + cyrf->status = CYRF6936_IDLE; + break; + } + break; + + /* Do a multi write */ + case CYRF6936_MULTIWRITE: + // When the last transaction isn't failed send the next + if(cyrf->spi_t.status != SPITransFailed) + cyrf->buffer_idx++; + + cyrf->spi_t.status = SPITransDone; + + // When we are done writing + if(cyrf->buffer_idx == cyrf->buffer_length) { + cyrf->status = CYRF6936_IDLE; + break; + } + + // Write the next register from the buffer + cyrf6936_write_register(cyrf, + ((uint8_t (*)[2])cyrf->buffer)[cyrf->buffer_idx][0], + ((uint8_t (*)[2])cyrf->buffer)[cyrf->buffer_idx][1]); + break; + + /* Do a write of channel, sop, data and crc */ + case CYRF6936_CHAN_SOP_DATA_CRC: + // When the last transaction isn't failed send the next + if(cyrf->spi_t.status != SPITransFailed) + cyrf->buffer_idx++; + + cyrf->spi_t.status = SPITransDone; + + // Switch for the different states + switch (cyrf->buffer_idx) { + case 0: // Write the CRC LSB + cyrf6936_write_register(cyrf, CYRF_CRC_SEED_LSB, cyrf->buffer[0]); + break; + case 1: // Write the CRC MSB + cyrf6936_write_register(cyrf, CYRF_CRC_SEED_MSB, cyrf->buffer[1]); + break; + case 2: // Write the SOP code + cyrf6936_write_block(cyrf, CYRF_SOP_CODE, &(cyrf->buffer[2]), 8); + break; + case 3: // Write the DATA code + cyrf6936_write_block(cyrf, CYRF_DATA_CODE, &(cyrf->buffer[10]), 16); + break; + case 4: // Write the Channel + cyrf6936_write_register(cyrf, CYRF_CHANNEL, cyrf->buffer[26]); + break; + default: + cyrf->status = CYRF6936_IDLE; + break; + } + break; + + /* Do a read of the receive irq status, receive status and the receive packet */ + case CYRF6936_RX_IRQ_STATUS_PACKET: + // When the last transaction isn't failed send the next + if(cyrf->spi_t.status != SPITransFailed) + cyrf->buffer_idx++; + + cyrf->spi_t.status = SPITransDone; + + // Switch for the different states + switch (cyrf->buffer_idx) { + case 0: // Read the receive IRQ status + cyrf6936_read_register(cyrf, CYRF_RX_IRQ_STATUS); + break; + case 1: // Read the receive status + cyrf->rx_irq_status = cyrf->input_buf[1]; + cyrf6936_read_register(cyrf, CYRF_RX_STATUS); + break; + case 2: // Read the receive packet + cyrf->rx_status = cyrf->input_buf[1]; + cyrf6936_read_block(cyrf, CYRF_RX_BUFFER, 16); + break; + default: + // Copy the receive packet + for(i = 0; i < 16; i++) + cyrf->rx_packet[i] = cyrf->input_buf[i+1]; + + cyrf->status = CYRF6936_IDLE; + break; + } + break; + + /* This should not happen */ + default: + break; + } +} + +/** + * Write a byte to a register + */ +static bool_t cyrf6936_write_register(struct Cyrf6936 *cyrf, const uint8_t addr, const uint8_t data) { + return cyrf6936_write_block(cyrf, addr, &data, 1); +} + +/** + * Write multiple bytes to a register + */ +static bool_t cyrf6936_write_block(struct Cyrf6936 *cyrf, const uint8_t addr, const uint8_t data[], const uint8_t length) { + uint8_t i; + /* Check if there is already a SPI transaction busy */ + if(cyrf->spi_t.status != SPITransDone) + return FALSE; + + /* Set the buffer and commit the transaction */ + cyrf->spi_t.output_length = length+1; + cyrf->spi_t.input_length = 0; + cyrf->output_buf[0] = addr | CYRF_DIR; + + // Copy the data + for(i = 0; i < length; i++) + cyrf->output_buf[i+1] = data[i]; + + // Submit the transaction + return spi_submit(cyrf->spi_p, &(cyrf->spi_t)); +} + +/** + * Read a byte from a register + */ +static bool_t cyrf6936_read_register(struct Cyrf6936 *cyrf, const uint8_t addr) { + return cyrf6936_read_block(cyrf, addr, 1); +} + +/** + * Read multiple bytes from a register + */ +static bool_t cyrf6936_read_block(struct Cyrf6936 *cyrf, const uint8_t addr, const uint8_t length) { + if(cyrf->spi_t.status != SPITransDone) + return FALSE; + + /* Set the buffer and commit the transaction */ + cyrf->spi_t.output_length = 1; + cyrf->spi_t.input_length = length + 1; + cyrf->output_buf[0] = addr; + + // Submit the transaction + return spi_submit(cyrf->spi_p, &(cyrf->spi_t)); +} + + +/** + * Write to multiple registers one byte + */ +bool_t cyrf6936_multi_write(struct Cyrf6936 *cyrf, const uint8_t data[][2], const uint8_t length) { + uint8_t i; + /* Check if the cyrf6936 isn't busy */ + if(cyrf->status != CYRF6936_IDLE) + return FALSE; + + // Set the status + cyrf->status = CYRF6936_MULTIWRITE; + + /* Set the multi write */ + cyrf->buffer_length = length; + cyrf->buffer_idx = 0; + + // Copy the buffer + for(i = 0; i< length; i++) { + cyrf->buffer[i*2] = data[i][0]; + cyrf->buffer[i*2+1] = data[i][1]; + } + + /* Write the first regiter */ + if(length > 0) + cyrf6936_write_register(cyrf, data[0][0], data[0][1]); + + return TRUE; +} + +/** + * Set the channel, SOP code, DATA code and the CRC seed + */ +bool_t cyrf6936_write_chan_sop_data_crc(struct Cyrf6936 *cyrf, const uint8_t chan, const uint8_t sop_code[], const uint8_t data_code[], const uint16_t crc_seed) { + uint8_t i; + /* Check if the cyrf6936 isn't busy */ + if(cyrf->status != CYRF6936_IDLE) + return FALSE; + + // Set the status + cyrf->status = CYRF6936_CHAN_SOP_DATA_CRC; + + // Copy the CRC + cyrf->buffer[0] = crc_seed & 0xFF; + cyrf->buffer[1] = (crc_seed >> 8) & 0xFF; + + // Copy the SOP code + for(i = 0; i < 8; i++) + cyrf->buffer[i+2] = sop_code[i]; + + // Copy the DATA code + for(i = 0; i < 16; i++) + cyrf->buffer[i+10] = data_code[i]; + + // Copy the channel + cyrf->buffer[26] = chan; + + /* Try to write the CRC LSB */ + cyrf->buffer_idx = 0; + cyrf6936_write_register(cyrf, CYRF_CRC_SEED_LSB, cyrf->buffer[0]); + + return TRUE; +} + +/** + * Read the RX IRQ status register, the rx status register and the rx packet + */ +bool_t cyrf6936_read_rx_irq_status_packet(struct Cyrf6936 *cyrf) { + /* Check if the cyrf6936 isn't busy */ + if(cyrf->status != CYRF6936_IDLE) + return FALSE; + + // Set the status + cyrf->status = CYRF6936_RX_IRQ_STATUS_PACKET; + + /* Try to read the RX status */ + cyrf->buffer_idx = 0; + cyrf6936_read_register(cyrf, CYRF_RX_IRQ_STATUS); + + return TRUE; +} diff --git a/sw/airborne/peripherals/cyrf6936.h b/sw/airborne/peripherals/cyrf6936.h new file mode 100644 index 0000000000..b7254ff026 --- /dev/null +++ b/sw/airborne/peripherals/cyrf6936.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2013 Freek van Tienen + * + * This file is part of paparazzi. + * + * paparazzi 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, or (at your option) + * any later version. + * + * paparazzi 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 paparazzi; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/** + * @file peripherals/yrf6936c.h + * Driver for the cyrf6936 2.4GHz radio chip + */ + +#ifndef CYRF6936_H +#define CYRF6936_H + +#include "cyrf6936_regs.h" +#include "mcu_periph/spi.h" + +#define CYRF6936_MAX_BUFFER 80 /**< The max buffer size in the cyrf6936 structure */ + +/* The different statuses the cyrf6936 chip can be in */ +enum Cyrf6936Status { + CYRF6936_UNINIT, /**< The chip isn't initialized */ + CYRF6936_IDLE, /**< The chip is idle and can be used */ + CYRF6936_GET_MFG_ID, /**< The chip is busy with getting the manufacturer ID */ + CYRF6936_MULTIWRITE, /**< The chip is writing multiple registers */ + CYRF6936_CHAN_SOP_DATA_CRC, /**< The chip is setting the channel, SOP code, DATA code and the CRC seed */ + CYRF6936_RX_IRQ_STATUS_PACKET /**< The chip is getting the receive irq status, receive status and the receive packet */ +}; + +/* The structure for the cyrf6936 chip that handles all the buffers and requests */ +struct Cyrf6936 { + struct spi_periph *spi_p; /**< The SPI peripheral for the connection */ + struct spi_transaction spi_t; /**< The SPI transaction used for the writing and reading of registers */ + volatile enum Cyrf6936Status status; /**< The status of the CYRF6936 chip */ + uint8_t input_buf[17]; /**< The input buffer for the SPI transaction */ + uint8_t output_buf[17]; /**< The output buffer for the SPI transaction */ + + uint8_t buffer[CYRF6936_MAX_BUFFER]; /**< The buffer used to write/read multiple registers */ + uint8_t buffer_length; /**< The length of the buffer used for MULTIWRITE */ + uint8_t buffer_idx; /**< The index of the buffer used for MULTIWRITE and used as sub-status for other statuses */ + + uint8_t mfg_id[6]; /**< The manufacturer id of the CYRF6936 chip */ + uint8_t rx_irq_status; /**< The last receive interrupt status */ + uint8_t rx_status; /**< The last receive status */ + uint8_t rx_packet[16]; /**< The last received packet */ +}; + +extern void cyrf6936_init(struct Cyrf6936 *cyrf, struct spi_periph *spi_p, const uint8_t slave_idx, const uint32_t rst_port, const uint16_t rst_pin); +void cyrf6936_event(struct Cyrf6936 *cyrf); + +bool_t cyrf6936_multi_write(struct Cyrf6936 *cyrf, const uint8_t data[][2], const uint8_t length); +bool_t cyrf6936_write_chan_sop_data_crc(struct Cyrf6936 *cyrf, const uint8_t chan, const uint8_t sop_code[], const uint8_t data_code[], const uint16_t crc_seed); +bool_t cyrf6936_read_rx_irq_status_packet(struct Cyrf6936 *cyrf); + +#endif /* CYRF6936_H */ diff --git a/sw/airborne/peripherals/cyrf6936_regs.h b/sw/airborne/peripherals/cyrf6936_regs.h new file mode 100644 index 0000000000..c5926771a7 --- /dev/null +++ b/sw/airborne/peripherals/cyrf6936_regs.h @@ -0,0 +1,211 @@ +/* + * Copyright (C) 2013 Freek van Tienen + * + * This file is part of paparazzi. + * + * paparazzi 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, or (at your option) + * any later version. + * + * paparazzi 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 paparazzi; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/** + * @file peripherals/cyrf6936_regs.h + * Register defines for the CYRF6936 2.4GHz radio chip + */ + +#ifndef CYRF6936_REGS_H +#define CYRF6936_REGS_H + +/* The SPI interface defines */ +enum { + CYRF_CHANNEL = 0x00, + CYRF_TX_LENGTH = 0x01, + CYRF_TX_CTRL = 0x02, + CYRF_TX_CFG = 0x03, + CYRF_TX_IRQ_STATUS = 0x04, + CYRF_RX_CTRL = 0x05, + CYRF_RX_CFG = 0x06, + CYRF_RX_IRQ_STATUS = 0x07, + CYRF_RX_STATUS = 0x08, + CYRF_RX_COUNT = 0x09, + CYRF_RX_LENGTH = 0x0A, + CYRF_PWR_CTRL = 0x0B, + CYRF_XTAL_CTRL = 0x0C, + CYRF_IO_CFG = 0x0D, + CYRF_GPIO_CTRL = 0x0E, + CYRF_XACT_CFG = 0x0F, + CYRF_FRAMING_CFG = 0x10, + CYRF_DATA32_THOLD = 0x11, + CYRF_DATA64_THOLD = 0x12, + CYRF_RSSI = 0x13, + CYRF_EOP_CTRL = 0x14, + CYRF_CRC_SEED_LSB = 0x15, + CYRF_CRC_SEED_MSB = 0x16, + CYRF_TX_CRC_LSB = 0x17, + CYRF_TX_CRC_MSB = 0x18, + CYRF_RX_CRC_LSB = 0x19, + CYRF_RX_CRC_MSB = 0x1A, + CYRF_TX_OFFSET_LSB = 0x1B, + CYRF_TX_OFFSET_MSB = 0x1C, + CYRF_MODE_OVERRIDE = 0x1D, + CYRF_RX_OVERRIDE = 0x1E, + CYRF_TX_OVERRIDE = 0x1F, + CYRF_TX_BUFFER = 0x20, + CYRF_RX_BUFFER = 0x21, + CYRF_SOP_CODE = 0x22, + CYRF_DATA_CODE = 0x23, + CYRF_PREAMBLE = 0x24, + CYRF_MFG_ID = 0x25, + CYRF_XTAL_CFG = 0x26, + CYRF_CLK_OFFSET = 0x27, + CYRF_CLK_EN = 0x28, + CYRF_RX_ABORT = 0x29, + CYRF_AUTO_CAL_TIME = 0x32, + CYRF_AUTO_CAL_OFFSET = 0x35, + CYRF_ANALOG_CTRL = 0x39, +}; +#define CYRF_DIR (1<<7) /**< Bit for enabling writing */ + +// CYRF_MODE_OVERRIDE +#define CYRF_RST (1<<0) + +// CYRF_CLK_EN +#define CYRF_RXF (1<<1) + +// CYRF_XACT_CFG +enum { + CYRF_MODE_SLEEP = (0x0 <<2), + CYRF_MODE_IDLE = (0x1 <<2), + CYRF_MODE_SYNTH_TX = (0x2 <<2), + CYRF_MODE_SYNTH_RX = (0x3 <<2), + CYRF_MODE_RX = (0x4 <<2), +}; +#define CYRF_FRC_END (1<<5) +#define CYRF_ACK_EN (1<<7) + +// CYRF_IO_CFG +#define CYRF_IRQ_GPIO (1<<0) +#define CYRF_SPI_3PIN (1<<1) +#define CYRF_PACTL_GPIO (1<<2) +#define CYRF_PACTL_OD (1<<3) +#define CYRF_XOUT_OD (1<<4) +#define CYRF_MISO_OD (1<<5) +#define CYRF_IRQ_POL (1<<6) +#define CYRF_IRQ_OD (1<<7) + +// CYRF_FRAMING_CFG +#define CYRF_LEN_EN (1<<5) +#define CYRF_SOP_LEN (1<<6) +#define CYRF_SOP_EN (1<<7) + +// CYRF_RX_STATUS +enum { + CYRF_RX_DATA_MODE_GFSK = 0x00, + CYRF_RX_DATA_MODE_8DR = 0x01, + CYRF_RX_DATA_MODE_DDR = 0x10, + CYRF_RX_DATA_MODE_NV = 0x11, +}; +#define CYRF_RX_CODE (1<<2) +#define CYRF_BAD_CRC (1<<3) +#define CYRF_CRC0 (1<<4) +#define CYRF_EOP_ERR (1<<5) +#define CYRF_PKT_ERR (1<<6) +#define CYRF_RX_ACK (1<<7) + +// CYRF_TX_IRQ_STATUS +#define CYRF_TXE_IRQ (1<<0) +#define CYRF_TXC_IRQ (1<<1) +#define CYRF_TXBERR_IRQ (1<<2) +#define CYRF_TXB0_IRQ (1<<3) +#define CYRF_TXB8_IRQ (1<<4) +#define CYRF_TXB15_IRQ (1<<5) +#define CYRF_LV_IRQ (1<<6) +#define CYRF_OS_IRQ (1<<7) + +// CYRF_RX_IRQ_STATUS +#define CYRF_RXE_IRQ (1<<0) +#define CYRF_RXC_IRQ (1<<1) +#define CYRF_RXBERR_IRQ (1<<2) +#define CYRF_RXB1_IRQ (1<<3) +#define CYRF_RXB8_IRQ (1<<4) +#define CYRF_RXB16_IRQ (1<<5) +#define CYRF_SOPDET_IRQ (1<<6) +#define CYRF_RXOW_IRQ (1<<7) + +// CYRF_TX_CTRL +#define CYRF_TXE_IRQEN (1<<0) +#define CYRF_TXC_IRQEN (1<<1) +#define CYRF_TXBERR_IRQEN (1<<2) +#define CYRF_TXB0_IRQEN (1<<3) +#define CYRF_TXB8_IRQEN (1<<4) +#define CYRF_TXB15_IRQEN (1<<5) +#define CYRF_TX_CLR (1<<6) +#define CYRF_TX_GO (1<<7) + +// CYRF_RX_CTRL +#define CYRF_RXE_IRQEN (1<<0) +#define CYRF_RXC_IRQEN (1<<1) +#define CYRF_RXBERR_IRQEN (1<<2) +#define CYRF_RXB1_IRQEN (1<<3) +#define CYRF_RXB8_IRQEN (1<<4) +#define CYRF_RXB16_IRQEN (1<<5) +#define CYRF_RSVD (1<<6) +#define CYRF_RX_GO (1<<7) + +// CYRF_RX_OVERRIDE +#define CYRF_ACE (1<<1) +#define CYRF_DIS_RXCRC (1<<2) +#define CYRF_DIS_CRC0 (1<<3) +#define CYRF_FRC_RXDR (1<<4) +#define CYRF_MAN_RXACK (1<<5) +#define CYRF_RXTX_DLY (1<<6) +#define CYRF_ACK_RX (1<<7) + +// CYRF_TX_OVERRIDE +#define CYRF_TX_INV (1<<0) +#define CYRF_DIS_TXCRC (1<<2) +#define CYRF_OVRD_ACK (1<<3) +#define CYRF_MAN_TXACK (1<<4) +#define CYRF_FRC_PRE (1<<6) +#define CYRF_ACK_TX (1<<7) + +// CYRF_RX_CFG +#define CYRF_VLD_EN (1<<0) +#define CYRF_RXOW_EN (1<<1) +#define CYRF_FAST_TURN_EN (1<<3) +#define CYRF_HILO (1<<4) +#define CYRF_ATT (1<<5) +#define CYRF_LNA (1<<6) +#define CYRF_AGC_EN (1<<7) + +// CYRF_TX_CFG +enum { + CYRF_PA_M35 = 0x0, + CYRF_PA_M30 = 0x1, + CYRF_PA_M24 = 0x2, + CYRF_PA_M18 = 0x3, + CYRF_PA_M13 = 0x4, + CYRF_PA_M5 = 0x5, + CYRF_PA_0 = 0x6, + CYRF_PA_4 = 0x7, +}; +enum { + CYRF_DATA_MODE_GFSK = (0x0 <<3), + CYRF_DATA_MODE_8DR = (0x1 <<3), + CYRF_DATA_MODE_DDR = (0x2 <<3), + CYRF_DATA_MODE_SDR = (0x3 <<3), +}; +#define CYRF_DATA_CODE_LENGTH (1<<5) + +#endif // CYRF6936_REGS_H diff --git a/sw/airborne/subsystems/radio_control/superbitrf.c b/sw/airborne/subsystems/radio_control/superbitrf.c new file mode 100644 index 0000000000..8f51d733eb --- /dev/null +++ b/sw/airborne/subsystems/radio_control/superbitrf.c @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2013 Freek van Tienen + * + * This file is part of paparazzi. + * + * paparazzi 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, or (at your option) + * any later version. + * + * paparazzi 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 paparazzi; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/** + * @file subsystems/radio_control/superbitrf.c + * DSM2 and DSMX implementation for the cyrf6936 2.4GHz radio chip trough SPI + */ + +#include "superbitrf.h" + +#include "subsystems/radio_control.h" +#include "mcu_periph/spi.h" +#include + +/* Default SuperbitRF SPI DEV */ +#ifndef SUPERBITRF_SPI_DEV +#define SUPERBITRF_SPI_DEV spi1 +#endif + +/* Default SuperbitRF RST PORT and PIN */ +#ifndef SUPERBITRF_RST_PORT +#define SUPERBITRF_RST_PORT GPIOC +#endif +#ifndef SUPERBITRF_RST_PIN +#define SUPERBITRF_RST_PIN GPIO12 +#endif + +/* Default SuperbitRF DRDY(IRQ) PORT and PIN */ +#ifndef SUPERBITRF_DRDY_PORT +#define SUPERBITRF_DRDY_PORT GPIOB +#endif +#ifndef SUPERBITRF_DRDY_PIN +#define SUPERBITRF_DRDY_PIN GPIO1 +#endif + +/* The superbitRF structure */ +struct SuperbitRF superbitrf; + +/* The startup configuration for the cyrf6936 */ +static const uint8_t cyrf_stratup_config[][2] = { + {CYRF_MODE_OVERRIDE, CYRF_RST}, // Reset the device + {CYRF_CLK_EN, CYRF_RXF}, // Enable the clock + {CYRF_AUTO_CAL_TIME, 0x3C}, // From manual, needed for initialization + {CYRF_AUTO_CAL_OFFSET, 0x14}, // From manual, needed for initialization + {CYRF_RX_CFG, CYRF_LNA | CYRF_FAST_TURN_EN}, // Enable low noise amplifier and fast turning + {CYRF_TX_OFFSET_LSB, 0x55}, // From manual, typical configuration + {CYRF_TX_OFFSET_MSB, 0x05}, // From manual, typical configuration + {CYRF_XACT_CFG, CYRF_MODE_SYNTH_RX | CYRF_FRC_END}, // Force in Synth RX mode + {CYRF_TX_CFG, CYRF_DATA_CODE_LENGTH | CYRF_DATA_MODE_SDR | CYRF_PA_4}, // Enable 64 chip codes, SDR mode and amplifier +4dBm + {CYRF_DATA64_THOLD, 0x0E}, // From manual, typical configuration + {CYRF_XACT_CFG, CYRF_MODE_SYNTH_RX}, // Set in Synth RX mode (again, really needed?) +}; +/* The binding configuration for the cyrf6936 */ +static const uint8_t cyrf_bind_config[][2] = { + {CYRF_TX_CFG, CYRF_DATA_CODE_LENGTH | CYRF_DATA_MODE_SDR | CYRF_PA_4}, // Enable 64 chip codes, SDR mode and amplifier +4dBm + {CYRF_FRAMING_CFG, CYRF_SOP_LEN | 0xE}, // Set SOP CODE to 64 chips and SOP Correlator Threshold to 0xE + {CYRF_RX_OVERRIDE, CYRF_FRC_RXDR | CYRF_DIS_RXCRC}, // Force receive data rate and disable receive CRC checker + {CYRF_EOP_CTRL, 0x02}, // Only enable EOP symbol count of 2 + {CYRF_TX_OVERRIDE, CYRF_DIS_TXCRC}, // Disable transmit CRC generate +}; + +/** + * Initialize the superbitrf + */ +void radio_control_impl_init(void) { + // Set the status to uninitialized + superbitrf.status = SUPERBITRF_UNINIT; + + // Initialize the binding pin + gpio_setup_input(SPEKTRUM_BIND_PIN_PORT, SPEKTRUM_BIND_PIN); + + // Initialize the cyrf6936 chip + cyrf6936_init(&superbitrf.cyrf6936, &(SUPERBITRF_SPI_DEV), 1, SUPERBITRF_RST_PORT, SUPERBITRF_RST_PIN); +} + +/** + * The superbitrf on event call + */ +void superbitrf_event(void) { + // Check the status + switch(superbitrf.status) { + + /* When the superbitrf isn't initialized */ + case SUPERBITRF_UNINIT: + // Try to write the startup config + if(cyrf6936_multi_write(&superbitrf.cyrf6936, cyrf_stratup_config, 11)) { + // Check if need to go to bind or transfer + if(gpio_get(SPEKTRUM_BIND_PIN_PORT, SPEKTRUM_BIND_PIN) == 0) + superbitrf.status = SUPERBITRF_INIT_BINDING; + else + superbitrf.status = SUPERBITRF_INIT_TRANSFER; + } + break; + + /* When the superbitrf is initializing binding */ + case SUPERBITRF_INIT_BINDING: + // Try to write the binding config + if(cyrf6936_multi_write(&superbitrf.cyrf6936, cyrf_bind_config, 5)) + superbitrf.status = SUPERBITRF_BINDING; + break; + + /* When the superbitrf is in binding mode */ + case SUPERBITRF_BINDING: + break; + + /* Should not come here */ + default: + break; + } + +} diff --git a/sw/airborne/subsystems/radio_control/superbitrf.h b/sw/airborne/subsystems/radio_control/superbitrf.h new file mode 100644 index 0000000000..a9f7e20dcf --- /dev/null +++ b/sw/airborne/subsystems/radio_control/superbitrf.h @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2013 Freek van Tienen + * + * This file is part of paparazzi. + * + * paparazzi 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, or (at your option) + * any later version. + * + * paparazzi 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 paparazzi; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +/** + * @file subsystems/radio_control/superbitrf.h + * DSM2 and DSMX implementation for the cyrf6936 2.4GHz radio chip trough SPI + */ + +#ifndef RADIO_CONTROL_SUPERBITRF_H +#define RADIO_CONTROL_SUPERBITRF_H + +#include "peripherals/cyrf6936.h" +#include "mcu_periph/gpio.h" + +/* Theoretically you could have 14 channel over DSM2/DSMX */ +#ifndef RADIO_CONTROL_NB_CHANNEL +#define RADIO_CONTROL_NB_CHANNEL 14 +#endif + +/* The channel ordering is always the same for DSM2 and DSMX */ +#define RADIO_THROTTLE 0 +#define RADIO_ROLL 1 +#define RADIO_PITCH 2 +#define RADIO_YAW 3 +#define RADIO_GEAR 4 +#define RADIO_FLAP 5 +#define RADIO_AUX1 5 +#define RADIO_AUX2 6 +#define RADIO_AUX3 7 +#define RADIO_AUX4 8 +#define RADIO_AUX5 9 +#define RADIO_AUX6 10 +#define RADIO_AUX7 11 +#define RADIO_AUX8 12 +#define RADIO_AUX9 13 + +/* Map the MODE default to the gear switch */ +#ifndef RADIO_MODE +#define RADIO_MODE RADIO_GEAR +#endif + +/* The different statuses the superbitRF can be in */ +enum SuperbitRFStatus { + SUPERBITRF_UNINIT, /**< The chip isn't initialized */ + SUPERBITRF_INIT_BINDING, /**< The chip is initializing binding mode */ + SUPERBITRF_INIT_TRANSFER, /**< The chip is initializing transfer mode */ + SUPERBITRF_BINDING, /**< The chip is in binding mode */ + SUPERBITRF_TRANSFER, /**< The chip is in transfer mode */ +}; + +/* The superbitrf structure */ +struct SuperbitRF { + struct Cyrf6936 cyrf6936; /**< The cyrf chip used */ + volatile enum SuperbitRFStatus status; /**< The status of the superbitRF */ +}; + +/* The superbitrf functions and structures */ +extern struct SuperbitRF superbitrf; +void superbitrf_event(void); + +/* The radio control event handler */ +#define RadioControlEvent(_received_frame_handler) { \ + cyrf6936_event(&superbitrf.cyrf6936); \ + superbitrf_event(); \ +} + +#endif /* RADIO_CONTROL_SUPERBITRF_H */