Drivers for various devices.

For now, only nRF24 driver.
2 files changed, 467 insertions(+), 0 deletions(-)

A => nrf24.c
A => nrf24.h
A => nrf24.c +427 -0
@@ 0,0 1,427 @@ 
+#include <debugio.h>
+#include <string.h>
+#include <ctl_api.h>
+#include <ctl_spi.h>
+#include <stdbool.h>
+#include <sam.h>
+
+#include "d2x_gpio.h"
+#include "d2x_eic.h"
+#include "d2x_common.h"
+
+#include "nrf24.h"
+
+#define RF24_CONFIG_ADDR 0x00
+#define RF24_EN_RXADDR 0x02
+#define RF24_SETUP_ADDR_LEN_ADDR 0x03
+#define RF24_RF_CH_ADDR  0x05
+#define RF24_STATUS_ADDR 0x07
+#define RF24_RX_ADDR_P0_ADDR 0x0A // location of pipe 0 rx address
+#define RF24_RX_ADDR_P1_ADDR 0x0B // location of pipe 1 rx address
+#define RF24_RX_PW_P0_ADDR 0x11   // Payload len of (rx) pipe 0
+
+
+
+#define RF24_TX_ADDR_ADDR 0x10 // location of tx address
+
+#define RF24_R_REGISTER    0x00
+#define RF24_W_REGISTER    0x20
+#define RF24_REGISTER_MASK 0x1F
+#define RF24_ACTIVATE      0x50
+#define R_RX_PL_WID   0x60
+#define R_RX_PAYLOAD  0x61
+#define W_TX_PAYLOAD  0xA0
+#define W_ACK_PAYLOAD 0xA8
+#define FLUSH_TX      0xE1
+#define FLUSH_RX      0xE2
+#define REUSE_TX_PL   0xE3
+#define RF24_NOP           0xFF
+
+#define MAX_PIPE_AMOUNT 6 // pipes 0..5
+
+// -- config register --
+#define MASK_RX_DR (1 << 6)
+#define MASK_TX_DS (1 << 5)
+#define MASK_MAX_RT (1 << 4)
+#define EN_CRC (1 << 3)
+#define CRC0 (1 << 2)
+#define PWR_UP (1 << 1)
+#define PRIM_RX (1 << 0)
+
+#define RF24_SERCOM 0
+
+const struct rf24_settings rf24_defaults =
+  {
+    .data_received_interrupt = false,
+    .data_sent_interrupt = false,
+    .max_retransmission_interrupt = false,
+    .enable_crc = true,
+    .use_2_bit_crc = false,
+    .power_up = false,
+    .rx_mode = false
+  };
+
+static CTL_SPI_DEVICE_t nrf24_device;
+
+static uint8_t rf24_addr_len = 0;
+
+static void rf24_cs(bool state)
+{
+  gpio_set_state(D2X_PORT_A, 5, state);
+}
+
+void rf24_select(struct CTL_SPI_DEVICE_s *self, int state)
+{
+  gpio_set_state(D2X_PORT_A, 5, state);
+}
+
+static void rf24_ce(bool state)
+{
+  gpio_set_state(D2X_PORT_A, 17, state);
+}
+
+uint8_t rf24_read_register_array(uint8_t reg, uint8_t *buf, uint32_t len)
+{
+  CTL_STATUS_t transfer_status, read_status;
+  uint32_t i;
+  uint8_t data;
+  uint8_t command = RF24_R_REGISTER | ( RF24_REGISTER_MASK & reg );
+
+  ctl_spi_select_device(&nrf24_device);
+  transfer_status = ctl_spi_exchange(&nrf24_device, &command, &data, 1);
+  if (transfer_status != CTL_NO_ERROR) {
+    debug_printf("read_register_array, transfer error: %d\n", transfer_status);
+  }
+
+  read_status = ctl_spi_read(&nrf24_device, buf, len);
+  if (read_status != CTL_NO_ERROR) {
+    debug_printf("read_register_array, read error: %d\n", read_status);
+  }
+
+  ctl_spi_deselect_device(&nrf24_device);
+
+  return transfer_status;
+}
+
+uint8_t rf24_read_register(uint8_t reg)
+{
+  CTL_STATUS_t transfer_status, read_status;
+  uint32_t i;
+  uint8_t data;
+  uint8_t command = RF24_R_REGISTER | ( RF24_REGISTER_MASK & reg );
+
+  ctl_spi_select_device(&nrf24_device);
+  transfer_status = ctl_spi_exchange(&nrf24_device, &command, &data, 1);
+  if (transfer_status != CTL_NO_ERROR) {
+    debug_printf("read_register, transfer error: %d\n", transfer_status);
+  }
+
+  command = 0xFF;
+  read_status = ctl_spi_exchange(&nrf24_device, &command, &data, 1);
+  if (read_status != CTL_NO_ERROR) {
+    debug_printf("rf24_read_register, read error: %d\n", read_status);
+  }
+  ctl_spi_deselect_device(&nrf24_device);
+
+  return data;
+
+}
+
+uint8_t rf24_write_register_array(uint8_t reg, const uint8_t *buf, uint32_t len)
+{
+  CTL_STATUS_t transfer_status, send_status;
+  uint32_t i;
+  uint8_t data;
+  uint8_t command = RF24_R_REGISTER | ( RF24_REGISTER_MASK & reg );
+
+  ctl_spi_select_device(&nrf24_device);
+  transfer_status = ctl_spi_exchange(&nrf24_device, &command, &data, 1);
+  if (transfer_status != CTL_NO_ERROR) {
+    debug_printf("write_register_array, transfer error: %d\n", transfer_status);
+  }
+
+  send_status = ctl_spi_write(&nrf24_device, buf, len);
+  if (send_status != CTL_NO_ERROR) {
+    debug_printf("write_register_array, send error: %d\n", send_status);
+  }
+  ctl_spi_deselect_device(&nrf24_device);
+
+  return data;
+
+}
+
+uint8_t rf24_write_register(uint8_t reg, uint8_t val)
+{
+  int transfer_status, write_status;
+  uint32_t i;
+  uint8_t data;
+  uint8_t command = RF24_R_REGISTER | ( RF24_REGISTER_MASK & reg );
+
+
+  ctl_spi_select_device(&nrf24_device);
+  transfer_status = ctl_spi_exchange(&nrf24_device, &command, &data, 1);
+  if (transfer_status != CTL_NO_ERROR) {
+    debug_printf("write_register, transfer error: %d\n", transfer_status);
+  }
+
+  command = val;
+  write_status = ctl_spi_write(&nrf24_device, &command, 1);
+  if (write_status != CTL_NO_ERROR) {
+    debug_printf("write_register, write error: %d\n", write_status);
+  }
+  
+  ctl_spi_deselect_device(&nrf24_device);
+  debug_printf("rf24_write_register ok\n");
+
+  return data;
+}
+
+uint8_t rf24_status(void)
+{
+  CTL_STATUS_t spi_status;
+  uint8_t rf_status;
+  uint8_t command = RF24_NOP;
+
+  ctl_spi_select_device(&nrf24_device);
+  spi_status = ctl_spi_exchange(&nrf24_device, &command, &rf_status, 1);
+  ctl_spi_deselect_device(&nrf24_device);
+
+  if (spi_status != CTL_NO_ERROR) {
+    debug_printf("ERROR: spi_transfer(NOP) failed\n");
+    return 0xFF;
+  }
+
+  return rf_status;
+}
+
+void rf24_set_channel(uint8_t ch)
+{
+  uint8_t s;
+  (void)rf24_write_register(RF24_RF_CH_ADDR, ch);
+  /* ignore return value */
+}
+
+void rf24_set_address_len(uint8_t addr_len)
+{
+  uint8_t len = addr_len;
+  if (len < 3) {
+    debug_printf("WARNING: Len %d too small, setting it to 3\n", len);
+    len = 3;
+  } else if (len > 5) {
+    debug_printf("WARNING: Len %d too big, setting it to 5\n", len);
+    len = 5;
+  }
+  (void)rf24_write_register(RF24_SETUP_ADDR_LEN_ADDR, len);
+  rf24_addr_len = len;
+}
+
+void rf24_set_rx_addr(uint8_t pipe_no, const uint8_t *addr, uint8_t addr_len)
+{
+  if (addr_len != rf24_addr_len) {
+    rf24_set_address_len(addr_len);
+  }
+
+  if (pipe_no > 1) {
+    debug_printf("ERROR: rf24_set_rx_addr: pipe number %d too big, doing nothing\n", pipe_no);
+    return;
+  }
+
+  if (addr == NULL) {
+    debug_printf("ERROR: rf24_set_rx_addr: addr NULL!\n");
+    return;
+  }
+
+  if (pipe_no == 0) {
+    (void)rf24_write_register_array(RF24_RX_ADDR_P0_ADDR, addr, rf24_addr_len);
+  } else {
+    (void)rf24_write_register_array(RF24_RX_ADDR_P1_ADDR, addr, rf24_addr_len);
+  }
+}
+
+void rf24_set_rx_payload_len(uint8_t pipe_no, uint8_t payload_len)
+{
+  uint8_t len = payload_len;
+
+  if (pipe_no >= MAX_PIPE_AMOUNT) {
+    debug_printf("ERROR: rf24_set_rx_payload_len: invalid pipe number %d\n", pipe_no);
+    return;
+  }
+
+  if (len > 32) {
+    len = 32;
+  }
+
+  (void)rf24_write_register(RF24_RX_PW_P0_ADDR + pipe_no, len);
+}
+
+int rf24_get_rx_payload_len(uint8_t pipe_no, uint8_t* payload_len)
+{
+  if (pipe_no >= MAX_PIPE_AMOUNT) {
+    debug_printf("ERROR: rf24_get_rx_payload_len: invalid pipe number %d\n", pipe_no);
+    return -1;
+  }
+  if (payload_len == NULL) {
+    debug_printf("ERROR: rf24_get_rx_payload_len: pointer NULL\n");
+    return -1;
+  }
+
+  *payload_len = rf24_read_register(RF24_RX_PW_P0_ADDR + pipe_no) & 0b00011111;
+
+  return 0;
+}
+
+int rf24_get_rx_payload(char *payload, uint8_t payload_max_len, uint8_t *len)
+{
+  CTL_STATUS_t transfer_status, read_status;
+  uint8_t data, command;
+  uint8_t payload_len = payload_max_len;
+
+  if (payload_len > 32) {
+    payload_len = 32;
+  }
+
+  command = R_RX_PAYLOAD;
+  ctl_spi_select_device(&nrf24_device);
+  transfer_status = ctl_spi_exchange(&nrf24_device, &command, &data, 1);
+
+  if (transfer_status != CTL_NO_ERROR) {
+    debug_printf("rf24_get_rx_payload, transfer error: %d\n", transfer_status);
+    return RF24_ERROR;
+  }
+
+  read_status = ctl_spi_read(&nrf24_device, payload, payload_len);
+  if (read_status != CTL_NO_ERROR) {
+    debug_printf("rf24_get_rx_payload, read error: %d\n", read_status);
+    return RF24_ERROR;
+  }
+  ctl_spi_deselect_device(&nrf24_device);
+
+  *len = payload_len;
+
+  return RF24_OK;
+}
+
+int rf24_set_tx_payload(const char *payload, uint8_t payload_len)
+{
+  CTL_STATUS_t transfer_status, send_status;
+  uint8_t data, command;
+
+  if (payload_len > 32) {
+    payload_len = 32;
+  }
+
+  command = W_TX_PAYLOAD;
+
+  ctl_spi_select_device(&nrf24_device);
+  transfer_status = ctl_spi_exchange(&nrf24_device, &command, &data, 1);
+  if (transfer_status != CTL_NO_ERROR) {
+    debug_printf("rf24_set_tx_payload, transfer error: %d\n", transfer_status);
+    rf24_cs(false);
+    return RF24_ERROR;
+  }
+
+  send_status = ctl_spi_write(&nrf24_device, payload, payload_len);
+  ctl_spi_deselect_device(&nrf24_device);
+
+  if (send_status != CTL_NO_ERROR) {
+    debug_printf("rf24_set_tx_payload, send error: %d\n", send_status);
+    return RF24_ERROR;
+  }
+
+  return RF24_OK;
+}
+
+void rf24_enable_pipes(uint8_t pipe_mask)
+{
+  (void)rf24_write_register(RF24_EN_RXADDR, pipe_mask & 0b00111111);
+}
+
+void rf24_set_tx_addr(const uint8_t *addr, uint8_t addr_len)
+{
+  if (addr_len != rf24_addr_len) {
+    rf24_set_address_len(addr_len);
+  }
+
+  (void)rf24_write_register_array(RF24_TX_ADDR_ADDR, addr, rf24_addr_len);
+}
+
+void rf24_get_config(struct rf24_settings* config)
+{
+  uint8_t conf;
+
+  conf = rf24_read_register(RF24_CONFIG_ADDR);
+
+  config->data_received_interrupt = (conf & MASK_RX_DR) == MASK_RX_DR;
+  config->data_sent_interrupt = (conf & MASK_TX_DS) == MASK_TX_DS;
+  config->max_retransmission_interrupt = (conf & MASK_MAX_RT) == MASK_MAX_RT;
+  config->enable_crc = (conf & EN_CRC) == EN_CRC;
+  config->use_2_bit_crc = (conf & CRC0) == CRC0;
+  config->power_up = (conf & PWR_UP) == PWR_UP;
+  config->rx_mode = (conf & PRIM_RX) == PRIM_RX;
+}
+
+void rf24_set_config(const struct rf24_settings *config)
+{
+  uint8_t conf;
+
+  if (config->data_received_interrupt) conf |= MASK_RX_DR;
+  if (config->data_sent_interrupt) conf |= MASK_TX_DS;
+  if (config->max_retransmission_interrupt) conf |= MASK_MAX_RT;
+  if (config->enable_crc) conf |= EN_CRC;
+  if (config->use_2_bit_crc) conf |= CRC0;
+  if (config->power_up) conf |= PWR_UP;
+  if (config->rx_mode) conf |= PRIM_RX;
+
+  (void)rf24_write_register(RF24_CONFIG_ADDR, conf);
+}
+
+void rf24_send_payload(void)
+{
+  rf24_ce(true);
+  ctl_timeout_wait(ctl_get_current_time() + ctl_get_ticks_per_second()/333); // ~3ms
+  rf24_ce(false);
+}
+
+void rf24_init(const struct rf24_settings *config, CTL_SPI_BUS_t *spi_bus)
+{
+  int status;
+  uint8_t s;
+  uint8_t addr[5] = { 0 };
+
+  rf24_addr_len = 5;
+
+
+  ctl_spi_attach_device(spi_bus, &nrf24_device);
+  nrf24_device.select = rf24_select;
+  ctl_spi_set_protocol(&nrf24_device, CTL_SPI_MODE0, 8, 100000, 0xFF);
+
+  // status = spi_enable(0, SPI_EDGE_FIRST_RISING);
+
+  // debug_printf("spi_enable: %d\n", status);
+
+  /* CE pin as output */
+  status = gpio_set_output(D2X_PORT_A, 17);
+  status = gpio_set_output(D2X_PORT_A, 5);
+
+  rf24_ce(false);
+  rf24_cs(false);
+
+  ctl_sleep(10);
+
+  rf24_set_config(config);
+  if (config->rx_mode) {
+    debug_printf("RX mode\n");
+  } else {
+  debug_printf("TX mode\n");
+  }
+
+  s = rf24_read_register_array(0x0A, addr, 5);
+  debug_printf("rf24 default address: %02x %02x %02x %02x %02x\n", addr[0], addr[1], addr[2], addr[3], addr[4]); 
+
+  s = rf24_write_register(0x05, 76);
+  debug_printf("channel write status: %d\n", s);
+
+  s = rf24_read_register(0x05);
+  debug_printf("rf24 channel: %d\n", s);
+}
+

          
A => nrf24.h +40 -0
@@ 0,0 1,40 @@ 
+#ifndef NRF24_H
+#define NRF24_H
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#define RF24_STATUS_RX_DR  (1 << 6) // data ready
+#define RF24_STATUS_TX_DS  (1 << 5) // data sent
+#define RF24_STATUS_MAX_RT (1 << 4) // Maximum number of retransmits reached
+#define RF24_STATUS_RX_P_NO (1 << 1) // data pipe N ready for reading; 3 bits
+#define RF24_STATUS_RX_P_NO_MASK 0b00001110
+#define RF24_STATUS_TX_FULL (1 << 0) // TX FIFO full
+#define RF24_STATUS_MASK 0b01111111 // bits 0..6 are used in status
+
+#define RF24_OK 0
+#define RF24_ERROR -1
+
+struct rf24_settings {
+  bool data_received_interrupt;
+  bool data_sent_interrupt;
+  bool max_retransmission_interrupt;
+  bool enable_crc;
+  bool use_2_bit_crc; // otherwise only 1 bit
+  bool power_up;
+  bool rx_mode; // otherwise in tx mode
+};
+
+extern const struct rf24_settings rf24_defaults;
+
+void rf24_init(const struct rf24_settings *config, CTL_SPI_BUS_t *spi_bus);
+uint8_t rf24_status(void);
+void rf24_set_rx_addr(uint8_t pipe_no, const uint8_t *addr, uint8_t addr_len);
+void rf24_set_rx_payload_len(uint8_t pipe_no, uint8_t payload_len);
+int rf24_get_rx_payload(char *payload, uint8_t payload_max_len, uint8_t *len);
+int rf24_set_tx_payload(const char *payload, uint8_t payload_len);
+void rf24_enable_pipes(uint8_t pipe_mask);
+void rf24_set_tx_addr(const uint8_t *addr, uint8_t addr_len);
+void rf24_send_payload(void);
+
+#endif /* NRF24_H */
  No newline at end of file