Compare commits

...

2 Commits

Author SHA1 Message Date
Marc Poulhiès 7103c3e0b3 still working on GPIO 7 years ago
Marc Poulhiès 780c41b47c WIP for cc430 7 years ago
  1. 1
      boards/chronos/Makefile.features
  2. 61
      cpu/cc430/include/cc430_regs.h
  3. 34
      cpu/cc430/include/periph_cpu.h
  4. 240
      cpu/cc430/periph/gpio.c
  5. 187
      drivers/cc110x/cc110x-cc430.c
  6. 4
      drivers/cc110x/cc110x-spi.c
  7. 11
      drivers/cc110x/cc110x.c
  8. 116
      drivers/cc110x/include/cc110x-cc430.h
  9. 5
      drivers/include/cc110x.h

1
boards/chronos/Makefile.features

@ -1,6 +1,7 @@
# Put defined MCU peripherals here (in alphabetical order)
FEATURES_PROVIDED += periph_timer
FEATURES_PROVIDED += periph_rtc
FEATURES_PROVIDED += periph_gpio
# Various other features (if any)

61
cpu/cc430/include/cc430_regs.h

@ -50,6 +50,46 @@ typedef struct {
REG16 EX0; /**< expansion 0 */
} msp_timer_t;
/**
* @brief Digital I/O Port w/o interrupt functionality (P)
*/
typedef struct {
REG8 IN; /**< input data */
REG8 padding0;
REG8 OD; /**< output data */
REG8 padding1;
REG8 DIR; /**< pin direction */
REG8 padding2;
REG8 REN; /**< resistor pull config */
REG8 padding3;
REG8 DS; /**< resistor drive strength */
REG8 padding4;
REG8 SEL; /**< alternative function select */
} msp_port_t;
/**
* @brief Digital I/O Port with interrupt functionality (P1 & P2)
*/
typedef struct {
REG8 IN; /**< input data */
REG8 padding0;
REG8 OD; /**< output data */
REG8 padding1;
REG8 DIR; /**< pin direction */
REG8 padding2;
REG8 REN; /**< resistor pull config */
REG8 padding3;
REG8 DS; /**< resistor drive strength */
REG8 padding4;
REG8 SEL; /**< alternative function select */
REG8 padding5[14];
REG8 IES; /**< interrupt edge select */
REG8 padding7;
REG8 IE; /**< interrupt enable */
REG8 padding8;
REG8 IFG; /**< interrupt flag */
} msp_port_isr_t;
/**
* @brief Timer Control register bitmap
* @{
@ -105,6 +145,25 @@ typedef struct {
*/
#define TIMER_A0_BASE ((uint16_t)0x0340)
#define TIMER_A1_BASE ((uint16_t)0x0380)
#define PORT_A_BASE ((uint16_t)0x0200)
#define PORT_B_BASE ((uint16_t)0x0220)
#define PORT_C_BASE ((uint16_t)0x0240)
/** @} */
/**
* @brief Typing of base register objects
* @{
*/
#define TIMER_A0 ((msp_timer_t *)TIMER_A0_BASE)
#define TIMER_A1 ((msp_timer_t *)TIMER_A1_BASE)
#define PORT_1 ((msp_port_t*)PORT_A_BASE)
#define PORT_2 ((msp_port_t*)(PORT_A_BASE + 1))
#define PORT_3 ((msp_port_t*)PORT_B_BASE)
#define PORT_4 ((msp_port_t*)(PORT_B_BASE + 1))
#define PORT_5 ((msp_port_t*)(PORT_C_BASE))
/** @} */
/**
@ -115,6 +174,8 @@ typedef struct {
#define TIMER_A1 ((msp_timer_t *)TIMER_A1_BASE)
/** @} */
#ifdef __cplusplus
}
#endif

34
cpu/cc430/include/periph_cpu.h

@ -1,5 +1,5 @@
/*
* Copyright (C) 2015 Freie Universität Berlin
* Copyright (C) 2015 Freie Universität Berlin
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
@ -14,6 +14,7 @@
* @brief CPU specific definitions for internal peripheral handling
*
* @author Hauke Petersen <hauke.peterse@fu-berlin.de>
* @author Marc Poulhiès <dkm@kataplop.net>
*/
#ifndef CPU_PERIPH_H_
@ -26,8 +27,37 @@
extern "C" {
#endif
/* more to come here... */
/**
* @brief Define a custom type for GPIO pins
* @{
*/
#define HAVE_GPIO_T
typedef uint16_t gpio_t;
/** @} */
/**
* @brief Definition of a fitting UNDEF value
*/
#define GPIO_UNDEF (0xffff)
/**
* @brief Mandatory function for defining a GPIO pins
* @{
*/
#define GPIO_PIN(x, y) ((gpio_t)(((x & 0xff) << 8) | (1 << (y & 0xff))))
/** @} */
/**
* @brief Override direction values
* @{
*/
#define HAVE_GPIO_DIR_T
typedef enum {
GPIO_DIR_IN = 0x00, /**< configure pin as input */
GPIO_DIR_OUT = 0xff, /**< configure pin as output */
} gpio_dir_t;
/** @} */
#ifdef __cplusplus
}
#endif

240
cpu/cc430/periph/gpio.c

@ -0,0 +1,240 @@
/*
* Copyright (C) 2015 Freie Universität Berlin
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup cpu_cc430
* @{
*
* @file
* @brief Low-level GPIO driver implementation
*
* @author
*
* @}
*/
#include "cpu.h"
#include "bitarithm.h"
#include "periph/gpio.h"
/**
* @brief Number of possible interrupt lines: 2 ports * 8 pins
*/
#define ISR_NUMOF (16U)
/**
* @brief Number of pins on each port
*/
#define PINS_PER_PORT (8U)
/**
* @brief Datatype to use for saving the interrupt contexts
*/
typedef struct {
gpio_cb_t cb; /**< callback to call on GPIO interrupt */
void *arg; /**< argument passed to the callback */
} isr_ctx_t;
/**
* @brief Interrupt context for each interrupt line
*/
static isr_ctx_t isr_ctx[ISR_NUMOF];
static msp_port_t *_port(gpio_t pin)
{
switch (pin >> 8) {
case 1:
return PORT_1;
case 2:
return PORT_2;
case 3:
return PORT_3;
case 4:
return PORT_4;
case 5:
return PORT_5;
default:
return NULL;
}
}
static inline msp_port_isr_t *_isr_port(gpio_t pin)
{
msp_port_t *p = _port(pin);
if ((p == PORT_1) || (p == PORT_2)) {
return (msp_port_isr_t *)p;
}
return NULL;
}
static inline uint8_t _pin(gpio_t pin)
{
return (uint8_t)(pin & 0xff);
}
static int _ctx(gpio_t pin)
{
int i = bitarithm_lsb(_pin(pin));
return (_port(pin) == PORT_1) ? i : (i + 8);
}
int gpio_init(gpio_t pin, gpio_dir_t dir, gpio_pp_t pullup)
{
msp_port_t *port = _port(pin);
/* check if port is valid and pull resistor are valid */
if (port == NULL ||
(dir == GPIO_DIR_OUT && pullup != GPIO_NOPULL)) {
return -1;
}
uint8_t pin_bit = _pin(pin);
/* set pin direction */
port->DIR &= ~(pin_bit);
port->DIR |= (dir & pin_bit);
if (dir == GPIO_DIR_OUT && pullup != GPIO_NOPULL){
port->REN |= 0xff & pin_bit;
if (pullup == GPIO_PULLUP){
port->OD |= 0xff & pin_bit;
} else { /* GPIO_PULLDOWN */
port->OD &= ~(pin_bit);
}
} else {
port->REN &= ~(pin_bit);
/* reset output value */
port->OD &= ~(pin_bit);
}
return 0;
}
int gpio_init_int(gpio_t pin, gpio_pp_t pullup, gpio_flank_t flank,
gpio_cb_t cb, void *arg)
{
msp_port_isr_t *port = _isr_port(pin);
/* check if port, pull resistor and flank configuration are valid */
if ((port == NULL) || (pullup != GPIO_NOPULL) || (flank == GPIO_BOTH)) {
return -1;
}
/* disable any activated interrupt */
port->IE &= ~(_pin(pin));
/* configure as input */
gpio_init(pin, GPIO_DIR_IN, GPIO_NOPULL);
/* save ISR context */
isr_ctx[_ctx(pin)].cb = cb;
isr_ctx[_ctx(pin)].arg = arg;
/* configure flank */
port->IES &= ~(_pin(pin));
port->IES |= (flank & _pin(pin));
/* clear pending interrupts and enable the IRQ */
port->IFG &= ~(_pin(pin));
gpio_irq_enable(pin);
return 0;
}
void gpio_periph_mode(gpio_t pin, bool enable)
{
REG8 *sel;
msp_port_isr_t *isrport = _isr_port(pin);
if (isrport) {
sel = &(isrport->SEL);
}
else {
msp_port_t *port = _port(pin);
if (port) {
sel = &(port->SEL);
}
else {
return;
}
}
if (enable) {
*sel |= _pin(pin);
}
else {
*sel &= ~(_pin(pin));
}
}
void gpio_irq_enable(gpio_t pin)
{
msp_port_isr_t *port = _isr_port(pin);
if (port) {
port->IE |= _pin(pin);
}
}
void gpio_irq_disable(gpio_t pin)
{
msp_port_isr_t *port = _isr_port(pin);
if (port) {
port->IE &= ~(_pin(pin));
}
}
int gpio_read(gpio_t pin)
{
msp_port_t *port = _port(pin);
if (port->DIR & _pin(pin)) {
return (int)(port->OD & _pin(pin));
}
else {
return (int)(port->IN & _pin(pin));
}
}
void gpio_set(gpio_t pin)
{
_port(pin)->OD |= _pin(pin);
}
void gpio_clear(gpio_t pin)
{
_port(pin)->OD &= ~(_pin(pin));
}
void gpio_toggle(gpio_t pin)
{
_port(pin)->OD ^= _pin(pin);
}
void gpio_write(gpio_t pin, int value)
{
if (value) {
_port(pin)->OD |= _pin(pin);
}
else {
_port(pin)->OD &= ~(_pin(pin));
}
}
static inline void isr_handler(msp_port_isr_t *port, int ctx)
{
for (int i = 0; i < PINS_PER_PORT; i++) {
if ((port->IE & (1 << i)) && (port->IFG & (1 << i))) {
port->IFG &= ~(1 << i);
isr_ctx[i + ctx].cb(isr_ctx[i + ctx].arg);
}
}
}
ISR(PORT1_VECTOR, isr_port1)
{
__enter_isr();
isr_handler((msp_port_isr_t *)PORT_1, 0);
__exit_isr();
}
ISR(PORT2_VECTOR, isr_port2)
{
__enter_isr();
isr_handler((msp_port_isr_t *)PORT_2, 8);
__exit_isr();
}

187
drivers/cc110x/cc110x-cc430.c

@ -0,0 +1,187 @@
/*
* Copyright (C) 2014 Freie Universität Berlin
* Copyright (C) 2015 Kaspar Schleiser <kaspar@schleiser.de>
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup drivers_cc110x
* @{
*
* @file
* @brief TI Chipcon CC110x spi driver
*
* @author Thomas Hillebrandt <hillebra@inf.fu-berlin.de>
* @author Heiko Will <hwill@inf.fu-berlin.de>
* @author Fabian Nack <nack@inf.fu-berlin.de>
* @author Joakim Gebart <joakim.gebart@eistec.se>
* @author Kaspar Schleiser <kaspar@schleiser.de>
* @}
*/
#ifdef __CC430__
#include <stdio.h>
#include "cc110x.h"
#include "cc110x-cc430.h"
#include "cc110x-internal.h"
#include "cc110x-defines.h"
#include "periph/gpio.h"
#include "xtimer.h"
#include "irq.h"
/**********************************************************************
* CC110x spi access
**********************************************************************/
void cc110x_cs(cc110x_t *dev)
{
/* volatile int retry_count = 0; */
/* /\* Switch MISO/GDO1 to GPIO input mode *\/ */
/* #ifndef GPIO_READS_SPI_PINS */
/* gpio_init(dev->params.gdo1, GPIO_DIR_IN, GPIO_NOPULL); */
/* #endif */
/* /\* CS to low *\/ */
/* gpio_clear(dev->params.cs); */
/* /\* Wait for SO to go low (voltage regulator */
/* * has stabilized and the crystal is running) *\/ */
/* while (gpio_read(dev->params.gdo1)) { */
/* /\* Wait ~500us and try again *\/ */
/* xtimer_usleep(CS_SO_WAIT_TIME); */
/* if (gpio_read(dev->params.gdo1)) { */
/* retry_count++; */
/* if (retry_count > CC110X_GDO1_LOW_RETRY) { */
/* puts("[CC110X spi] fatal error\n"); */
/* break; */
/* } */
/* gpio_set(dev->params.cs); */
/* gpio_clear(dev->params.cs); */
/* } */
/* } */
/* /\* Switch MISO/GDO1 to spi mode *\/ */
/* #ifndef GPIO_READS_SPI_PINS */
/* spi_conf_pins(dev->params.spi); */
/* #endif */
}
void cc110x_writeburst_reg(cc110x_t *dev, uint8_t addr, const char *src, uint8_t count)
{
/* unsigned int cpsr; */
/* spi_acquire(dev->params.spi); */
/* cpsr = disableIRQ(); */
/* cc110x_cs(dev); */
/* spi_transfer_regs(dev->params.spi, addr | CC110X_WRITE_BURST, (char *)src, 0, count); */
/* gpio_set(dev->params.cs); */
/* restoreIRQ(cpsr); */
/* spi_release(dev->params.spi); */
}
void cc110x_readburst_reg(cc110x_t *dev, uint8_t addr, char *buffer, uint8_t count)
{
/* int i = 0; */
/* unsigned int cpsr; */
/* spi_acquire(dev->params.spi); */
/* cpsr = disableIRQ(); */
/* cc110x_cs(dev); */
/* spi_transfer_byte(dev->params.spi, addr | CC110X_READ_BURST, 0); */
/* while (i < count) { */
/* spi_transfer_byte(dev->params.spi, CC110X_NOBYTE, &buffer[i]); */
/* i++; */
/* } */
/* gpio_set(dev->params.cs); */
/* restoreIRQ(cpsr); */
/* spi_release(dev->params.spi); */
}
void cc110x_write_reg(cc110x_t *dev, uint8_t addr, uint8_t value)
{
/* unsigned int cpsr; */
/* spi_acquire(dev->params.spi); */
/* cpsr = disableIRQ(); */
/* cc110x_cs(dev); */
/* spi_transfer_reg(dev->params.spi, addr, value, 0); */
/* gpio_set(dev->params.cs); */
/* restoreIRQ(cpsr); */
/* spi_release(dev->params.spi); */
}
uint8_t cc110x_read_reg(cc110x_t *dev, uint8_t addr)
{
char result;
/* unsigned int cpsr; */
/* spi_acquire(dev->params.spi); */
/* cpsr = disableIRQ(); */
/* cc110x_cs(dev); */
/* spi_transfer_reg(dev->params.spi, addr | CC110X_READ_SINGLE, CC110X_NOBYTE, &result); */
/* gpio_set(dev->params.cs); */
/* restoreIRQ(cpsr); */
/* spi_release(dev->params.spi); */
result = 0;
return (uint8_t) result;
}
uint8_t cc110x_read_status(cc110x_t *dev, uint8_t addr)
{
char result;
/* unsigned int cpsr; */
/* spi_acquire(dev->params.spi); */
/* cpsr = disableIRQ(); */
/* cc110x_cs(dev); */
/* spi_transfer_reg(dev->params.spi, addr | CC110X_READ_BURST, CC110X_NOBYTE, &result); */
/* gpio_set(dev->params.cs); */
/* restoreIRQ(cpsr); */
/* spi_release(dev->params.spi); */
result = 0;
return (uint8_t) result;
}
uint8_t cc110x_get_reg_robust(cc110x_t *dev, uint8_t addr)
{
/* char result, result2; */
/* unsigned int cpsr; */
/* spi_acquire(dev->params.spi); */
/* cpsr = disableIRQ(); */
/* cc110x_cs(dev); */
/* do { */
/* spi_transfer_reg(dev->params.spi, addr | CC110X_READ_BURST, CC110X_NOBYTE, &result); */
/* spi_transfer_reg(dev->params.spi, addr | CC110X_READ_BURST, CC110X_NOBYTE, &result2); */
/* } while (result != result2); */
/* gpio_set(dev->params.cs); */
/* restoreIRQ(cpsr); */
/* spi_release(dev->params.spi); */
/* return (uint8_t) result; */
return 0;
}
uint8_t cc110x_strobe(cc110x_t *dev, uint8_t c)
{
#ifdef CC110X_DONT_RESET
if (c == CC110X_SRES) {
return 0;
}
#endif
char result;
/* unsigned int cpsr; */
/* spi_acquire(dev->params.spi); */
/* cpsr = disableIRQ(); */
/* cc110x_cs(dev); */
/* spi_transfer_byte(dev->params.spi, c, &result); */
/* gpio_set(dev->params.cs); */
/* restoreIRQ(cpsr); */
/* spi_release(dev->params.spi); */
result = 0;
return (uint8_t) result;
}
#endif /* __CC430__ */

4
drivers/cc110x/cc110x-spi.c

@ -22,6 +22,8 @@
* @}
*/
#ifndef __CC430__
#include <stdio.h>
#include "cc110x.h"
@ -177,3 +179,5 @@ uint8_t cc110x_strobe(cc110x_t *dev, uint8_t c)
spi_release(dev->params.spi);
return (uint8_t) result;
}
#endif /* __CC430__ */

11
drivers/cc110x/cc110x.c

@ -23,7 +23,11 @@
#include "board.h"
#include "periph/cpuid.h"
#include "periph/gpio.h"
#ifndef __CC430__
#include "periph/spi.h"
#endif
#include "xtimer.h"
#include "cpu.h"
#include "log.h"
@ -33,7 +37,12 @@
#include "cc110x-defines.h"
#include "cc110x-interface.h"
#include "cc110x-internal.h"
#ifndef __CC430__
#include "cc110x-spi.h"
#else
#include "cc110x-cc430.h"
#endif
#define ENABLE_DEBUG (0)
#include "debug.h"
@ -61,10 +70,12 @@ int cc110x_setup(cc110x_t *dev, const cc110x_params_t *params)
/* Configure GDO1 */
gpio_init(dev->params.gdo1, GPIO_DIR_IN, GPIO_NOPULL);
#ifndef __CC430__
/* Configure SPI */
spi_acquire(dev->params.spi);
spi_init_master(dev->params.spi, SPI_CONF_FIRST_RISING, SPI_SPEED_5MHZ);
spi_release(dev->params.spi);
#endif /* __CC430__ */
#ifndef CC110X_DONT_RESET
/* reset device*/

116
drivers/cc110x/include/cc110x-cc430.h

@ -0,0 +1,116 @@
/*
* Copyright (C) 2014 Freie Universität Berlin
* Copyright (C) 2013 INRIA
* Copyright (C) 2015 Kaspar Schleiser <kaspar@schleiser.de>
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup drivers_cc110x
* @{
*
* @file
* @brief CC110X SPI functions
*
* @author Oliver Hahm <oliver.hahm@inria.fr>
* @author Fabian Nack <nack@inf.fu-berlin.de>
* @author Kaspar Schleiser <kaspar@schleiser.de>
*/
#ifndef CC110X_CC430_h_
#define CC110X_CC430_H
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Write a set of bytes using burst mode (if available)
*
* @param dev Device to work on
* @param addr Destination register
* @param buffer Data to be written
* @param count Size of data
*/
void cc110x_writeburst_reg(cc110x_t *dev, uint8_t addr, const char *buffer, uint8_t count);
/**
* @brief Read a set of bytes using burst mode (if available)
*
* @param dev Device to work on
* @param addr Source register
* @param buffer Buffer to store read data
* @param count Size of data to be read
*/
void cc110x_readburst_reg(cc110x_t *dev, uint8_t addr, char *buffer, uint8_t count);
/**
* @brief Write one byte to a register
*
* @param dev Device to work on
* @param addr Destinatoin register
* @param value New value
*/
void cc110x_write_reg(cc110x_t *dev, uint8_t addr, uint8_t value);
/**
* @brief Read a byte from register
*
* @param dev Device to work on
* @param addr Source register
*
* @return Read state and value of register
*/
uint8_t cc110x_read_reg(cc110x_t *dev, uint8_t addr);
/**
* @brief Read a byte from register, robust version
*
* Datasheet states some registered should be read twice until
* it returns the same value.
*
* @param dev Device to work on
* @param addr Source register
*
* @return Read state and value of register
*/
uint8_t cc110x_get_reg_robust(cc110x_t *dev, uint8_t addr);
/**
* @brief Read state of a register
*
* @param dev Device to work on
* @param addr Source register
*
* @return State of register
*/
uint8_t cc110x_read_status(cc110x_t *dev, uint8_t addr);
/**
* @brief Sends a command strobe
*
* @param dev Device to work on
* @param c Command code
*
* @return Command response
*/
uint8_t cc110x_strobe(cc110x_t *dev, uint8_t c);
/**
* @brief Pull CS to low and wait for CC110x stabilization
*
* @param dev Device to work on
*/
void cc110x_cs(cc110x_t *dev);
#ifdef __cplusplus
}
#endif
/** @} */
#endif /* CC110X_CC430_H */

5
drivers/include/cc110x.h

@ -24,7 +24,10 @@
extern "C" {
#endif
#ifndef __CC430__
#include "periph/spi.h"
#endif /* __CC430__ */
#include "periph/gpio.h"
#include "cc110x-internal.h"
@ -32,7 +35,9 @@ extern "C" {
* @brief Struct for holding cc110x IO parameters
*/
typedef struct cc110x_params {
#ifndef __CC430__
spi_t spi; /**< what */
#endif /* __CC430__ */
gpio_t cs; /**< does */
gpio_t gdo0; /**< this */
gpio_t gdo1; /**< look */

Loading…
Cancel
Save