nes-proj/arch/platform/zoul/dev/cc1200-zoul-arch.c
2018-04-04 11:30:32 +01:00

301 lines
11 KiB
C

/*
* Copyright (c) 2015, Zolertia
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*---------------------------------------------------------------------------*/
/**
* \addtogroup zoul
* @{
*
* \defgroup zoul-cc1200 Zoul CC1200 arch
*
* CC1200 Zoul arch specifics
* @{
*
* \file
* CC1200 Zoul arch specifics
*/
/*---------------------------------------------------------------------------*/
#include "contiki.h"
#include "contiki-net.h"
#include "dev/leds.h"
#include "reg.h"
#include "dev/spi-arch-legacy.h"
#include "dev/ioc.h"
#include "dev/sys-ctrl.h"
#include "dev/spi-legacy.h"
#include "dev/ssi.h"
#include "dev/gpio.h"
#include "dev/gpio-hal.h"
#include <stdio.h>
/*---------------------------------------------------------------------------*/
#define CC1200_SPI_CLK_PORT_BASE GPIO_PORT_TO_BASE(SPI0_CLK_PORT)
#define CC1200_SPI_CLK_PIN_MASK GPIO_PIN_MASK(SPI0_CLK_PIN)
#define CC1200_SPI_MOSI_PORT_BASE GPIO_PORT_TO_BASE(SPI0_TX_PORT)
#define CC1200_SPI_MOSI_PIN_MASK GPIO_PIN_MASK(SPI0_TX_PIN)
#define CC1200_SPI_MISO_PORT_BASE GPIO_PORT_TO_BASE(SPI0_RX_PORT)
#define CC1200_SPI_MISO_PIN_MASK GPIO_PIN_MASK(SPI0_RX_PIN)
#define CC1200_SPI_CSN_PORT_BASE GPIO_PORT_TO_BASE(CC1200_SPI_CSN_PORT)
#define CC1200_SPI_CSN_PIN_MASK GPIO_PIN_MASK(CC1200_SPI_CSN_PIN)
#define CC1200_GDO0_PORT_BASE GPIO_PORT_TO_BASE(CC1200_GDO0_PORT)
#define CC1200_GDO0_PIN_MASK GPIO_PIN_MASK(CC1200_GDO0_PIN)
#define CC1200_GDO2_PORT_BASE GPIO_PORT_TO_BASE(CC1200_GDO2_PORT)
#define CC1200_GDO2_PIN_MASK GPIO_PIN_MASK(CC1200_GDO2_PIN)
#define CC1200_RESET_PORT_BASE GPIO_PORT_TO_BASE(CC1200_RESET_PORT)
#define CC1200_RESET_PIN_MASK GPIO_PIN_MASK(CC1200_RESET_PIN)
/*---------------------------------------------------------------------------*/
#ifndef DEBUG_CC1200_ARCH
#define DEBUG_CC1200_ARCH 0
#endif
/*---------------------------------------------------------------------------*/
#if DEBUG_CC1200_ARCH > 0
#define PRINTF(...) printf(__VA_ARGS__)
#define BUSYWAIT_UNTIL(cond, max_time) \
do { \
rtimer_clock_t t0; \
t0 = RTIMER_NOW(); \
while(!(cond) && RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + (max_time))) {} \
if(!(RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + (max_time)))) { \
printf("ARCH: Timeout exceeded in line %d!\n", __LINE__); \
} \
} while(0)
#else
#define PRINTF(...)
#define BUSYWAIT_UNTIL(cond, max_time) while(!cond)
#endif
/*---------------------------------------------------------------------------*/
extern int cc1200_rx_interrupt(void);
/*---------------------------------------------------------------------------*/
void
cc1200_int_handler(gpio_hal_pin_mask_t pin_mask)
{
/* To keep the gpio_register_callback happy */
cc1200_rx_interrupt();
}
/*---------------------------------------------------------------------------*/
void
cc1200_arch_spi_select(void)
{
/* Set CSn to low (0) */
GPIO_CLR_PIN(CC1200_SPI_CSN_PORT_BASE, CC1200_SPI_CSN_PIN_MASK);
/* The MISO pin should go low before chip is fully enabled. */
BUSYWAIT_UNTIL(
GPIO_READ_PIN(CC1200_SPI_MISO_PORT_BASE, CC1200_SPI_MISO_PIN_MASK) == 0,
RTIMER_SECOND / 100);
}
/*---------------------------------------------------------------------------*/
void
cc1200_arch_spi_deselect(void)
{
/* Set CSn to high (1) */
GPIO_SET_PIN(CC1200_SPI_CSN_PORT_BASE, CC1200_SPI_CSN_PIN_MASK);
}
/*---------------------------------------------------------------------------*/
int
cc1200_arch_spi_rw_byte(uint8_t c)
{
SPI_WAITFORTx_BEFORE();
SPIX_BUF(CC1200_SPI_INSTANCE) = c;
SPIX_WAITFOREOTx(CC1200_SPI_INSTANCE);
SPIX_WAITFOREORx(CC1200_SPI_INSTANCE);
c = SPIX_BUF(CC1200_SPI_INSTANCE);
return c;
}
/*---------------------------------------------------------------------------*/
int
cc1200_arch_spi_rw(uint8_t *inbuf, const uint8_t *write_buf, uint16_t len)
{
int i;
uint8_t c;
if((inbuf == NULL && write_buf == NULL) || len <= 0) {
return 1;
} else if(inbuf == NULL) {
for(i = 0; i < len; i++) {
SPI_WAITFORTx_BEFORE();
SPIX_BUF(CC1200_SPI_INSTANCE) = write_buf[i];
SPIX_WAITFOREOTx(CC1200_SPI_INSTANCE);
SPIX_WAITFOREORx(CC1200_SPI_INSTANCE);
c = SPIX_BUF(CC1200_SPI_INSTANCE);
/* read and discard to avoid "variable set but not used" warning */
(void)c;
}
} else if(write_buf == NULL) {
for(i = 0; i < len; i++) {
SPI_WAITFORTx_BEFORE();
SPIX_BUF(CC1200_SPI_INSTANCE) = 0;
SPIX_WAITFOREOTx(CC1200_SPI_INSTANCE);
SPIX_WAITFOREORx(CC1200_SPI_INSTANCE);
inbuf[i] = SPIX_BUF(CC1200_SPI_INSTANCE);
}
} else {
for(i = 0; i < len; i++) {
SPI_WAITFORTx_BEFORE();
SPIX_BUF(CC1200_SPI_INSTANCE) = write_buf[i];
SPIX_WAITFOREOTx(CC1200_SPI_INSTANCE);
SPIX_WAITFOREORx(CC1200_SPI_INSTANCE);
inbuf[i] = SPIX_BUF(CC1200_SPI_INSTANCE);
}
}
return 0;
}
/*---------------------------------------------------------------------------*/
static gpio_hal_event_handler_t interrupt_handler = {
.next = NULL,
.handler = cc1200_int_handler,
.pin_mask =
(gpio_hal_pin_to_mask(CC1200_GDO0_PIN) << (CC1200_GDO0_PORT << 3)) |
(gpio_hal_pin_to_mask(CC1200_GDO2_PIN) << (CC1200_GDO2_PORT << 3))
};
/*---------------------------------------------------------------------------*/
void
cc1200_arch_gpio0_setup_irq(int rising)
{
GPIO_SOFTWARE_CONTROL(CC1200_GDO0_PORT_BASE, CC1200_GDO0_PIN_MASK);
GPIO_SET_INPUT(CC1200_GDO0_PORT_BASE, CC1200_GDO0_PIN_MASK);
GPIO_DETECT_EDGE(CC1200_GDO0_PORT_BASE, CC1200_GDO0_PIN_MASK);
GPIO_TRIGGER_SINGLE_EDGE(CC1200_GDO0_PORT_BASE, CC1200_GDO0_PIN_MASK);
if(rising) {
GPIO_DETECT_RISING(CC1200_GDO0_PORT_BASE, CC1200_GDO0_PIN_MASK);
} else {
GPIO_DETECT_FALLING(CC1200_GDO0_PORT_BASE, CC1200_GDO0_PIN_MASK);
}
GPIO_ENABLE_INTERRUPT(CC1200_GDO0_PORT_BASE, CC1200_GDO0_PIN_MASK);
ioc_set_over(CC1200_GDO0_PORT, CC1200_GDO0_PIN, IOC_OVERRIDE_PUE);
NVIC_EnableIRQ(CC1200_GPIOx_VECTOR);
gpio_hal_register_handler(&interrupt_handler);
}
/*---------------------------------------------------------------------------*/
void
cc1200_arch_gpio2_setup_irq(int rising)
{
GPIO_SOFTWARE_CONTROL(CC1200_GDO2_PORT_BASE, CC1200_GDO2_PIN_MASK);
GPIO_SET_INPUT(CC1200_GDO2_PORT_BASE, CC1200_GDO2_PIN_MASK);
GPIO_DETECT_EDGE(CC1200_GDO2_PORT_BASE, CC1200_GDO2_PIN_MASK);
GPIO_TRIGGER_SINGLE_EDGE(CC1200_GDO2_PORT_BASE, CC1200_GDO2_PIN_MASK);
if(rising) {
GPIO_DETECT_RISING(CC1200_GDO2_PORT_BASE, CC1200_GDO2_PIN_MASK);
} else {
GPIO_DETECT_FALLING(CC1200_GDO2_PORT_BASE, CC1200_GDO2_PIN_MASK);
}
GPIO_ENABLE_INTERRUPT(CC1200_GDO2_PORT_BASE, CC1200_GDO2_PIN_MASK);
ioc_set_over(CC1200_GDO2_PORT, CC1200_GDO2_PIN, IOC_OVERRIDE_PUE);
NVIC_EnableIRQ(CC1200_GPIOx_VECTOR);
gpio_hal_register_handler(&interrupt_handler);
}
/*---------------------------------------------------------------------------*/
void
cc1200_arch_gpio0_enable_irq(void)
{
GPIO_ENABLE_INTERRUPT(CC1200_GDO0_PORT_BASE, CC1200_GDO0_PIN_MASK);
ioc_set_over(CC1200_GDO0_PORT, CC1200_GDO0_PIN, IOC_OVERRIDE_PUE);
NVIC_EnableIRQ(CC1200_GPIOx_VECTOR);
}
/*---------------------------------------------------------------------------*/
void
cc1200_arch_gpio0_disable_irq(void)
{
GPIO_DISABLE_INTERRUPT(CC1200_GDO0_PORT_BASE, CC1200_GDO0_PIN_MASK);
}
/*---------------------------------------------------------------------------*/
void
cc1200_arch_gpio2_enable_irq(void)
{
GPIO_ENABLE_INTERRUPT(CC1200_GDO2_PORT_BASE, CC1200_GDO2_PIN_MASK);
ioc_set_over(CC1200_GDO2_PORT, CC1200_GDO2_PIN, IOC_OVERRIDE_PUE);
NVIC_EnableIRQ(CC1200_GPIOx_VECTOR);
}
/*---------------------------------------------------------------------------*/
void
cc1200_arch_gpio2_disable_irq(void)
{
GPIO_DISABLE_INTERRUPT(CC1200_GDO2_PORT_BASE, CC1200_GDO2_PIN_MASK);
}
/*---------------------------------------------------------------------------*/
int
cc1200_arch_gpio0_read_pin(void)
{
return (GPIO_READ_PIN(CC1200_GDO0_PORT_BASE, CC1200_GDO0_PIN_MASK) ? 1 : 0);
}
/*---------------------------------------------------------------------------*/
int
cc1200_arch_gpio2_read_pin(void)
{
return GPIO_READ_PIN(CC1200_GDO2_PORT_BASE, CC1200_GDO2_PIN_MASK);
}
/*---------------------------------------------------------------------------*/
int
cc1200_arch_gpio3_read_pin(void)
{
return 0x00;
}
/*---------------------------------------------------------------------------*/
void
cc1200_arch_init(void)
{
/* First leave RESET high */
GPIO_SOFTWARE_CONTROL(CC1200_RESET_PORT_BASE, CC1200_RESET_PIN_MASK);
GPIO_SET_OUTPUT(CC1200_RESET_PORT_BASE, CC1200_RESET_PIN_MASK);
ioc_set_over(CC1200_RESET_PORT, CC1200_RESET_PIN, IOC_OVERRIDE_OE);
GPIO_SET_PIN(CC1200_RESET_PORT_BASE, CC1200_RESET_PIN_MASK);
/* Initialize CSn, enable CSn and then wait for MISO to go low*/
spix_cs_init(CC1200_SPI_CSN_PORT, CC1200_SPI_CSN_PIN);
/* Initialize SPI */
spix_init(CC1200_SPI_INSTANCE);
/* Configure GPIOx */
GPIO_SOFTWARE_CONTROL(CC1200_GDO0_PORT_BASE, CC1200_GDO0_PIN_MASK);
GPIO_SET_INPUT(CC1200_GDO0_PORT_BASE, CC1200_GDO0_PIN_MASK);
GPIO_SOFTWARE_CONTROL(CC1200_GDO2_PORT_BASE, CC1200_GDO2_PIN_MASK);
GPIO_SET_INPUT(CC1200_GDO2_PORT_BASE, CC1200_GDO2_PIN_MASK);
/* Leave CSn as default */
cc1200_arch_spi_deselect();
/* Ensure MISO is high */
BUSYWAIT_UNTIL(
GPIO_READ_PIN(CC1200_SPI_MISO_PORT_BASE, CC1200_SPI_MISO_PIN_MASK),
RTIMER_SECOND / 10);
}
/*---------------------------------------------------------------------------*/
/**
* @}
* @}
*/