Merge pull request #1408 from simonduq/pr/jn516x-update

JN516x: tickless clock, power saving update, 32 kHz rtimer
This commit is contained in:
Simon Duquennoy 2015-12-03 14:59:53 +01:00
commit bc17cdca2c
14 changed files with 838 additions and 244 deletions

View File

@ -93,6 +93,14 @@ PROCESS_THREAD(border_router_process, ev, data)
rpl_tools_init(&prefix);
/* Print out routing tables every minute */
etimer_set(&et, CLOCK_SECOND * 60);
while(1) {
print_network_status();
PROCESS_YIELD_UNTIL(etimer_expired(&et));
etimer_reset(&et);
}
PROCESS_END();
}
/*---------------------------------------------------------------------------*/

View File

@ -58,6 +58,7 @@ AUTOSTART_PROCESSES(&node_process);
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(node_process, ev, data)
{
static struct etimer et;
PROCESS_BEGIN();
/* 3 possible roles:
@ -71,8 +72,6 @@ PROCESS_THREAD(node_process, ev, data)
#if CONFIG_VIA_BUTTON
{
#define CONFIG_WAIT_TIME 10
static struct etimer et;
SENSORS_ACTIVATE(button_sensor);
etimer_set(&et, CLOCK_SECOND * CONFIG_WAIT_TIME);
@ -103,6 +102,16 @@ PROCESS_THREAD(node_process, ev, data)
rpl_tools_init(&prefix);
} else {
rpl_tools_init(NULL);
} PROCESS_END();
}
/* Print out routing tables every minute */
etimer_set(&et, CLOCK_SECOND * 60);
while(1) {
print_network_status();
PROCESS_YIELD_UNTIL(etimer_expired(&et));
etimer_reset(&et);
}
PROCESS_END();
}
/*---------------------------------------------------------------------------*/

View File

@ -43,6 +43,54 @@
#define DEBUG DEBUG_PRINT
#include "net/ip/uip-debug.h"
/*---------------------------------------------------------------------------*/
void
print_network_status(void)
{
int i;
uint8_t state;
uip_ds6_defrt_t *default_route;
uip_ds6_route_t *route;
PRINTA("--- Network status ---\n");
/* Our IPv6 addresses */
PRINTA("- Server IPv6 addresses:\n");
for(i = 0; i < UIP_DS6_ADDR_NB; i++) {
state = uip_ds6_if.addr_list[i].state;
if(uip_ds6_if.addr_list[i].isused &&
(state == ADDR_TENTATIVE || state == ADDR_PREFERRED)) {
PRINTA("-- ");
uip_debug_ipaddr_print(&uip_ds6_if.addr_list[i].ipaddr);
PRINTA("\n");
}
}
/* Our default route */
PRINTA("- Default route:\n");
default_route = uip_ds6_defrt_lookup(uip_ds6_defrt_choose());
if(default_route != NULL) {
PRINTA("-- ");
uip_debug_ipaddr_print(&default_route->ipaddr);;
PRINTA(" (lifetime: %lu seconds)\n", (unsigned long)default_route->lifetime.interval);
} else {
PRINTA("-- None\n");
}
/* Our routing entries */
PRINTA("- Routing entries (%u in total):\n", uip_ds6_route_num_routes());
route = uip_ds6_route_head();
while(route != NULL) {
PRINTA("-- ");
uip_debug_ipaddr_print(&route->ipaddr);
PRINTA(" via ");
uip_debug_ipaddr_print(uip_ds6_route_nexthop(route));
PRINTA(" (lifetime: %lu seconds)\n", (unsigned long)route->state.lifetime);
route = uip_ds6_route_next(route);
}
PRINTA("----------------------\n");
}
/*---------------------------------------------------------------------------*/
static void
print_local_addresses(void)

View File

@ -33,3 +33,4 @@
*/
void rpl_tools_init(uip_ipaddr_t *br_prefix);
void print_network_status(void);

View File

@ -9,6 +9,11 @@ ifdef CHIP
else
JENNIC_CHIP ?= JN5168
endif
ifdef MODULE
JN5168_MODULE = $(MODULE)
else
JN5168_MODULE ?= M00
endif
JENNIC_PCB ?= DEVKIT4
JENNIC_STACK ?= MAC
JENNIC_MAC ?= MiniMac
@ -75,7 +80,8 @@ SIZE:=$(CROSS_COMPILE)-size
OBJCOPY:=$(CROSS_COMPILE)-objcopy
OBJDUMP:=$(CROSS_COMPILE)-objdump
ARCH = ccm-star.c exceptions.c rtimer-arch.c slip_uart0.c clock.c micromac-radio.c \
ARCH = ccm-star.c exceptions.c rtimer-arch.c rtimer-arch-slow.c \
slip_uart0.c clock.c micromac-radio.c \
mtarch.c node-id.c watchdog.c log.c ringbufindex.c slip.c sprintf.c
# Default uart0 for printf and slip
TARGET_WITH_UART0 ?= 1
@ -126,6 +132,10 @@ CONTIKI_TARGET_DIRS += dev/dongle
ARCH += leds-arch.c
endif
ifeq ($(JENNIC_CHIP),JN5168)
CFLAGS += -DJN5168_$(JN5168_MODULE)
endif
ifdef nodemac
CFLAGS += -DMACID=$(nodemac)
endif

View File

@ -44,10 +44,14 @@ The following features have been implemented:
* A radio driver with two modes (polling and interrupt based)
* CCM* driver with HW accelerated AES
* UART driver (with HW and SW flow control, 1'000'000 baudrate by default)
* Contiki system clock and rtimers (16MHz tick frequency based on 32 MHz crystal)
* 32.768kHz external oscillator
* Contiki tickless clock
* Contiki rtimers based on either
* the 32 kHz external oscillator
* or the internal 32 MHz oscillator (which gives a 16 MHz rtimer)
* CPU low-power mdoes
* doze mode: shallow sleep, 32 MHz oscillator (source of rtimer and radio clock) keeps running
* sleep mode: deeper sleep, 32 MHz oscillator turned off, next wakeup set on 32 kHz oscillator
* Periodic DCO recalibration
* CPU "doze" mode
* HW random number generator used as a random seed for pseudo-random generator
* Watchdog, JN516x HW exception handlers
@ -60,7 +64,6 @@ The following hardware platforms have been tested:
## TODO list
The following features are planned:
* CPU deeper sleep mode support (where the 32 MHz crystal is turned off)
* Time-accurate radio primitives ("send at", "listen until")
* External storage
@ -157,12 +160,31 @@ The following MCU models are supported:
Set `CHIP` variable to change this; for example, to select JN5164 use:
`make CHIP=JN5164`
The JN5168 has four module variants available:
* `M00` - Standard power, integrated antenna (default module)
* `M03` - Standard power, uFL connector
* `M05` - Medium power, uFL connector
* `M06` - High power, uFL connector
The `M05` and `M06` need to control the internal power amplifier. Set the `MODULE` variable to select the module, for example:
`make CHIP=JN5168 MODULE=M05`
The following platform-specific configurations are supported:
* DR1174 evaluation kit; enable this with `JN516x_WITH_DR1174 = 1` in your makefile
* DR1174 with DR1175 sensor board; enable this with `JN516x_WITH_DR1175 = 1` (will set `JN516x_WITH_DR1174` automatically)
* DR1174 with DR1199 sensor board; enable this with `JN516x_WITH_DR1199 = 1` (will set `JN516x_WITH_DR1174` automatically)
* USB dongle; enable this with `JN516x_WITH_DONGLE = 1`
### Enabling specific hardware features
The JN516X Contiki platform supports sleep mode (with RAM retention and keeping the external oscillator on). To enable sleeping, configure `JN516X_SLEEP_CONF_ENABLED=1`.
Sleeping will only happen if there at least 50 ms until the next rtimer or etimer. Also, the system will wake up ~10 ms before the next timer should fire in order to reinitialize all hardware peripherals.
The JN516X Contiki platform also supports rtimers at two different speeds: 16 MHz and 32 kHz. By default, the high-speed timer is used. The two timers have similar expected accuracy (drift ppm), but the 16 MHz one has higher precision. However, the low-speed timers are also kept running during sleeping.
To enable the low-frequency timer option, set `RTIMER_USE_32KHZ=1`. An external crystal oscillator is required to achieve reasonable accuracy in this case. This oscilator is present on most platforms, and is enabled automatically if either 32kHz timers or sleeping are enabled.
### Node IEEE/RIME/IPv6 Addresses
Nodes will autoconfigure their IPv6 address based on their 64-bit IEEE/MAC address. The 64-bit MAC address is read directly from JN516x System on Chip.

View File

@ -37,6 +37,7 @@
*
* \author
* Beshr Al Nahas <beshr@sics.se>
* Atis Elsts <atis.elsts@sics.se>
*/
#include <stdio.h>
@ -48,6 +49,7 @@
#include <BbcAndPhyRegs.h>
#include <recal.h>
#include "dev/uart0.h"
#include "dev/uart-driver.h"
#include "contiki.h"
#include "net/netstack.h"
@ -113,6 +115,17 @@ static uint8_t is_gateway;
#include "experiment-setup.h"
#endif
/* _EXTRA_LPM is the sleep mode, _LPM is the doze mode */
#define ENERGEST_TYPE_EXTRA_LPM ENERGEST_TYPE_LPM
static void main_loop(void);
#if DCOSYNCH_CONF_ENABLED
static unsigned long last_dco_calibration_time;
#endif
static uint64_t sleep_start;
static uint32_t sleep_start_ticks;
/*---------------------------------------------------------------------------*/
#define DEBUG 1
#if DEBUG
@ -255,25 +268,17 @@ set_linkaddr(void)
#endif
}
/*---------------------------------------------------------------------------*/
#if USE_EXTERNAL_OSCILLATOR
static bool_t
init_xosc(void)
bool_t
xosc_init(void)
{
/* The internal 32kHz RC oscillator is used by default;
* Initialize and enable the external 32.768kHz crystal.
*/
vAHI_Init32KhzXtal();
/* wait for 1.0 seconds for the crystal to stabilize */
clock_time_t start = clock_time();
clock_time_t now;
do {
now = clock_time();
watchdog_periodic();
} while(now - start < CLOCK_SECOND);
/* switch to the 32.768 kHz crystal */
/* Switch to the 32.768kHz crystal.
* This will block and wait up to 1 sec for it to stabilize. */
return bAHI_Set32KhzClockMode(E_AHI_XTAL);
}
#endif
/*---------------------------------------------------------------------------*/
#if WITH_TINYOS_AUTO_IDS
uint16_t TOS_NODE_ID = 0x1234; /* non-zero */
@ -285,7 +290,23 @@ main(void)
/* Set stack overflow address for detecting overflow in runtime */
vAHI_SetStackOverflow(TRUE, ((uint32_t *)&heap_location)[0]);
/* Initialize random with a seed from the SoC random generator.
* This must be done before selecting the high-precision external oscillator.
*/
vAHI_StartRandomNumberGenerator(E_AHI_RND_SINGLE_SHOT, E_AHI_INTS_DISABLED);
random_init(u16AHI_ReadRandomNumber());
clock_init();
rtimer_init();
#if JN516X_EXTERNAL_CRYSTAL_OSCILLATOR
/* initialize the 32kHz crystal and wait for ready */
xosc_init();
/* need to reinitialize because the wait-for-ready process uses system timers */
clock_init();
rtimer_init();
#endif
watchdog_init();
leds_init();
leds_on(LEDS_ALL);
@ -308,20 +329,10 @@ main(void)
}
#endif
/* Initialize random with a seed from the SoC random generator.
* This must be done before selecting the high-precision external oscillator.
*/
vAHI_StartRandomNumberGenerator(E_AHI_RND_SINGLE_SHOT, E_AHI_INTS_DISABLED);
random_init(u16AHI_ReadRandomNumber());
process_init();
ctimer_init();
uart0_init(UART_BAUD_RATE); /* Must come before first PRINTF */
#if USE_EXTERNAL_OSCILLATOR
init_xosc();
#endif
#if NETSTACK_CONF_WITH_IPV4
slip_arch_init(UART_BAUD_RATE);
#endif /* NETSTACK_CONF_WITH_IPV4 */
@ -403,10 +414,27 @@ main(void)
#if NETSTACK_CONF_WITH_IPV6
start_uip6();
#endif /* NETSTACK_CONF_WITH_IPV6 */
/* need this to reliably generate the first rtimer callback and callbacks in other
auto-start processes */
(void)u32AHI_Init();
start_autostart_processes();
leds_off(LEDS_ALL);
main_loop();
return -1;
}
static void
main_loop(void)
{
int r;
clock_time_t time_to_etimer;
rtimer_clock_t ticks_to_rtimer;
while(1) {
do {
/* Reset watchdog. */
@ -423,9 +451,8 @@ main(void)
* if we have more than 500uSec until next rtimer
* PS: Calibration disables interrupts and blocks for 200uSec.
* */
static unsigned long last_dco_calibration_time = 0;
if(clock_seconds() - last_dco_calibration_time > DCOSYNCH_PERIOD) {
if(rtimer_arch_get_time_until_next_wakeup() > RTIMER_SECOND / 2000) {
if(rtimer_arch_time_to_rtimer() > RTIMER_SECOND / 2000) {
/* PRINTF("ContikiMain: Calibrating the DCO\n"); */
eAHI_AttemptCalibration();
/* Patch to allow CpuDoze after calibration */
@ -434,15 +461,51 @@ main(void)
}
}
#endif /* DCOSYNCH_CONF_ENABLED */
ENERGEST_OFF(ENERGEST_TYPE_CPU);
ENERGEST_ON(ENERGEST_TYPE_LPM);
vAHI_CpuDoze();
watchdog_start();
ENERGEST_OFF(ENERGEST_TYPE_LPM);
ENERGEST_ON(ENERGEST_TYPE_CPU);
}
return 0;
/* flush standard output before sleeping */
uart_driver_flush(E_AHI_UART_0);
/* calculate the time to the next etimer and rtimer */
time_to_etimer = clock_arch_time_to_etimer();
ticks_to_rtimer = rtimer_arch_time_to_rtimer();
#if JN516X_SLEEP_ENABLED
/* we can sleep only up to the next rtimer/etimer */
rtimer_clock_t max_sleep_time = ticks_to_rtimer;
if(max_sleep_time >= JN516X_MIN_SLEEP_TIME) {
/* also take into account etimers */
uint64_t ticks_to_etimer = ((uint64_t)time_to_etimer * RTIMER_SECOND) / CLOCK_SECOND;
max_sleep_time = MIN(ticks_to_etimer, ticks_to_rtimer);
}
if(max_sleep_time >= JN516X_MIN_SLEEP_TIME) {
max_sleep_time -= JN516X_SLEEP_GUARD_TIME;
/* bound the sleep time to 1 second */
max_sleep_time = MIN(max_sleep_time, JN516X_MAX_SLEEP_TIME);
#if !RTIMER_USE_32KHZ
/* convert to 32.768 kHz oscillator ticks */
max_sleep_time = (uint64_t)max_sleep_time * JN516X_XOSC_SECOND / RTIMER_SECOND;
#endif
vAHI_WakeTimerEnable(WAKEUP_TIMER, TRUE);
/* sync with the tick timer */
WAIT_FOR_EDGE(sleep_start);
sleep_start_ticks = u32AHI_TickTimerRead();
vAHI_WakeTimerStartLarge(WAKEUP_TIMER, max_sleep_time);
ENERGEST_SWITCH(ENERGEST_TYPE_CPU, ENERGEST_TYPE_EXTRA_LPM);
vAHI_Sleep(E_AHI_SLEEP_OSCON_RAMON);
} else {
#else
{
#endif /* JN516X_SLEEP_ENABLED */
clock_arch_schedule_interrupt(time_to_etimer, ticks_to_rtimer);
ENERGEST_SWITCH(ENERGEST_TYPE_CPU, ENERGEST_TYPE_LPM);
vAHI_CpuDoze();
watchdog_start();
ENERGEST_SWITCH(ENERGEST_TYPE_LPM, ENERGEST_TYPE_CPU);
}
}
}
/*---------------------------------------------------------------------------*/
void
@ -456,7 +519,52 @@ void
AppWarmStart(void)
{
/* Wakeup after sleep with memory on.
* TODO: Need to initialize devices but not the application state */
main();
* Need to initialize devices but not the application state.
* Note: the actual time this function is called is
* ~8 ticks (32kHz timer) later than the scheduled sleep end time.
*/
uint32_t sleep_ticks;
uint64_t sleep_end;
rtimer_clock_t sleep_ticks_rtimer;
clock_arch_calibrate();
leds_init();
uart0_init(UART_BAUD_RATE); /* Must come before first PRINTF */
NETSTACK_RADIO.init();
watchdog_init();
watchdog_stop();
WAIT_FOR_EDGE(sleep_end);
sleep_ticks = (uint32_t)(sleep_start - sleep_end) + 1;
#if RTIMER_USE_32KHZ
sleep_ticks_rtimer = sleep_ticks;
#else
{
static uint32_t remainder;
uint64_t t = (uint64_t)sleep_ticks * RTIMER_SECOND + remainder;
sleep_ticks_rtimer = (uint32_t)(t / JN516X_XOSC_SECOND);
remainder = t - sleep_ticks_rtimer * JN516X_XOSC_SECOND;
}
#endif
/* reinitialize rtimers */
rtimer_arch_reinit(sleep_start_ticks, sleep_ticks_rtimer);
ENERGEST_SWITCH(ENERGEST_TYPE_EXTRA_LPM, ENERGEST_TYPE_CPU);
watchdog_start();
/* reinitialize clock */
clock_arch_init(1);
/* schedule etimer interrupt */
clock_arch_schedule_interrupt(clock_arch_time_to_etimer(), rtimer_arch_time_to_rtimer());
#if DCOSYNCH_CONF_ENABLED
/* The radio is recalibrated on wakeup */
last_dco_calibration_time = clock_seconds();
#endif
main_loop();
}
/*---------------------------------------------------------------------------*/

View File

@ -32,9 +32,10 @@
/**
* \file
* Clock implementation for NXP jn516x.
* Tickless clock implementation for NXP jn516x.
* \author
* Beshr Al Nahas <beshr@sics.se>
* Atis Elsts <atis.elsts@sics.se>
*
*/
@ -47,10 +48,6 @@
#include "rtimer-arch.h"
#include "dev/watchdog.h"
/**
* TickTimer will be used for RTIMER
* E_AHI_TIMER_1 will be used for ticking
**/
#define DEBUG 0
#if DEBUG
@ -60,84 +57,95 @@
#define PRINTF(...)
#endif
static volatile unsigned long seconds = 0;
static volatile uint8_t ticking = 0;
static volatile clock_time_t clock_ticks = 0;
/* last_tar is used for calculating clock_fine */
#define CLOCK_TIMER E_AHI_TIMER_1
#define CLOCK_TIMER_ISR_DEV E_AHI_DEVICE_TIMER1
/* 16Mhz / 2^7 = 125Khz */
#define CLOCK_PRESCALE 7
/* 10ms tick --> overflow after ~981/2 days */
#define CLOCK_INTERVAL (125 * 10)
#define MAX_TICKS (CLOCK_INTERVAL)
#define CLOCK_TIMER_ISR_DEV E_AHI_DEVICE_TIMER1
#define OVERFLOW_TIMER E_AHI_TIMER_0
#define OVERFLOW_TIMER_ISR_DEV E_AHI_DEVICE_TIMER0
/* 16Mhz / 2^10 = 15.625 kHz */
#define CLOCK_PRESCALE 10
#define PRESCALED_TICKS_PER_SECOND 15625
/* 8ms tick --> overflow after ~397.7 days */
#define CLOCK_INTERVAL 125
/* Max schedulable number of ticks.
* Must not be more than:
* 0xffff / (16'000'000 / (1 << CLOCK_PRESCALE) / CLOCK_SECOND)
*/
#define CLOCK_MAX_SCHEDULABLE_TICKS 520
/* Min guard time an etimer can be scheduled before an rtimer */
#define CLOCK_RTIMER_GUARD_TIME US_TO_RTIMERTICKS(16)
/* Clock tick expressed as rtimer ticks */
#define CLOCK_TICK ((1 << CLOCK_PRESCALE) * CLOCK_INTERVAL)
#define RTIMER_OVERFLOW_PRESCALED 4194304 /* = 0x100000000 / (2^CLOCK_PRESCALE) */
#define RTIMER_OVERFLOW_REMAINDER 54 /* in prescaled ticks, per one overflow */
#define CLOCK_LT(a, b) ((int32_t)((a)-(b)) < 0)
/*---------------------------------------------------------------------------*/
static uint32_t
clock(void)
{
/* same as rtimer_arch_now() */
return u32AHI_TickTimerRead();
}
/*---------------------------------------------------------------------------*/
static uint32_t
check_rtimer_overflow(rtimer_clock_t now)
{
static rtimer_clock_t last_rtimer_ticks;
static uint32_t clock_ticks_remainder;
static uint32_t clock_ticks_base;
if(last_rtimer_ticks > now) {
clock_ticks_base += RTIMER_OVERFLOW_PRESCALED / CLOCK_INTERVAL;
clock_ticks_remainder += RTIMER_OVERFLOW_REMAINDER;
if(clock_ticks_remainder > CLOCK_INTERVAL) {
clock_ticks_remainder -= CLOCK_INTERVAL;
clock_ticks_base += 1;
}
}
last_rtimer_ticks = now;
return clock_ticks_base;
}
/*---------------------------------------------------------------------------*/
static void
check_etimers(void)
{
if(etimer_pending()) {
clock_time_t now = clock_time();
if(!CLOCK_LT(now, etimer_next_expiration_time())) {
etimer_request_poll();
}
}
process_nevents();
}
/*---------------------------------------------------------------------------*/
void
clockTimerISR(uint32 u32Device, uint32 u32ItemBitmap)
{
if(u32Device != CLOCK_TIMER_ISR_DEV) {
if(u32Device != CLOCK_TIMER_ISR_DEV && u32Device != OVERFLOW_TIMER_ISR_DEV) {
return;
}
ENERGEST_ON(ENERGEST_TYPE_IRQ);
watchdog_start();
clock_ticks++;
if(clock_ticks % CLOCK_CONF_SECOND == 0) {
++seconds;
energest_flush();
}
if(etimer_pending() && (etimer_next_expiration_time() - clock_ticks - 1) > MAX_TICKS) {
etimer_request_poll();
/* TODO exit low-power mode */
}
if(process_nevents() >= 0) {
/* TODO exit low-power mode */
if(u32Device == CLOCK_TIMER_ISR_DEV) {
check_etimers();
}
watchdog_stop();
if(u32Device == OVERFLOW_TIMER_ISR_DEV) {
check_rtimer_overflow(clock());
}
ENERGEST_OFF(ENERGEST_TYPE_IRQ);
}
/*---------------------------------------------------------------------------*/
static void
clock_timer_init(void)
{
vAHI_TimerEnable(CLOCK_TIMER, CLOCK_PRESCALE, 0, 1, 0);
vAHI_TimerClockSelect(CLOCK_TIMER, 0, 0);
vAHI_TimerConfigureOutputs(CLOCK_TIMER, 0, 1);
vAHI_TimerDIOControl(CLOCK_TIMER, 0);
#if (CLOCK_TIMER == E_AHI_TIMER_0)
vAHI_Timer0RegisterCallback(clockTimerISR);
#elif (CLOCK_TIMER == E_AHI_TIMER_1)
vAHI_Timer1RegisterCallback(clockTimerISR);
#endif
clock_ticks = 0;
vAHI_TimerStartRepeat(CLOCK_TIMER, 0, CLOCK_INTERVAL);
ticking = 1;
}
/*---------------------------------------------------------------------------*/
void
clock_init(void)
clock_arch_calibrate(void)
{
/* gMAC_u8MaxBuffers = 2; */
#ifdef JENNIC_CHIP_FAMILY_JN516x
/* Turn off debugger */
*(volatile uint32 *)0x020000a0 = 0;
#endif
/* system controller interrupts callback is disabled
* -- Only wake Interrupts --
*/
vAHI_SysCtrlRegisterCallback(0);
/* schedule clock tick interrupt */
clock_timer_init();
rtimer_init();
(void)u32AHI_Init();
bAHI_SetClockRate(E_AHI_XTAL_32MHZ);
/* Wait for oscillator to stabilise */
@ -151,27 +159,55 @@ clock_init(void)
| REG_SYSCTRL_PWRCTRL_SPIMEN_MASK);
}
/*---------------------------------------------------------------------------*/
clock_time_t
clock_time(void)
void
clock_arch_init(int is_reinitialization)
{
clock_time_t t1, t2;
do {
t1 = clock_ticks;
t2 = clock_ticks;
} while(t1 != t2);
return t1;
/* initialize etimer interrupt timer */
vAHI_TimerEnable(CLOCK_TIMER, CLOCK_PRESCALE, 0, 1, 0);
vAHI_TimerClockSelect(CLOCK_TIMER, 0, 0);
vAHI_TimerConfigureOutputs(CLOCK_TIMER, 0, 1);
vAHI_TimerDIOControl(CLOCK_TIMER, 0);
vAHI_Timer1RegisterCallback(clockTimerISR);
/* initialize and start rtimer overflow timer */
vAHI_TimerEnable(OVERFLOW_TIMER, CLOCK_PRESCALE, 0, 1, 0);
vAHI_TimerClockSelect(OVERFLOW_TIMER, 0, 0);
vAHI_TimerConfigureOutputs(OVERFLOW_TIMER, 0, 1);
vAHI_TimerDIOControl(OVERFLOW_TIMER, 0);
vAHI_Timer0RegisterCallback(clockTimerISR);
vAHI_TimerStartRepeat(OVERFLOW_TIMER, 0, PRESCALED_TICKS_PER_SECOND * 4);
if(is_reinitialization) {
/* check if the etimer has overflowed (useful when this is executed after sleep */
check_rtimer_overflow(clock());
}
}
/*---------------------------------------------------------------------------*/
void
clock_set(clock_time_t clock, clock_time_t fclock)
clock_init(void)
{
clock_ticks = clock;
/* gMAC_u8MaxBuffers = 2; */
#ifdef JENNIC_CHIP_FAMILY_JN516x
/* Turn off debugger */
*(volatile uint32 *)0x020000a0 = 0;
#endif
clock_arch_calibrate();
/* setup clock mode and interrupt handler */
clock_arch_init(0);
}
/*---------------------------------------------------------------------------*/
int
clock_fine_max(void)
clock_time_t
clock_time(void)
{
return CLOCK_INTERVAL;
uint32_t now = clock();
clock_time_t base = check_rtimer_overflow(now);
return base + now / CLOCK_TICK;
}
/*---------------------------------------------------------------------------*/
/**
@ -180,33 +216,19 @@ clock_fine_max(void)
void
clock_delay_usec(uint16_t dt)
{
volatile uint32_t t = u32AHI_TickTimerRead();
#define RTIMER_MAX_TICKS 0xffffffff
/* beware of wrapping */
if(RTIMER_MAX_TICKS - t < dt) {
while(u32AHI_TickTimerRead() < RTIMER_MAX_TICKS && u32AHI_TickTimerRead() != 0) ;
dt -= RTIMER_MAX_TICKS - t;
t = 0;
}
while(u32AHI_TickTimerRead() - t < dt) {
watchdog_periodic();
}
uint32_t end = clock() + dt;
/* Note: this does not call watchdog periodic() */
while(CLOCK_LT(clock(), end));
}
/*---------------------------------------------------------------------------*/
/**
* Delay the CPU for a multiple of 8 us.
*/
void
clock_delay(unsigned int i)
clock_delay(unsigned int dt)
{
volatile uint32_t t = u16AHI_TimerReadCount(CLOCK_TIMER);
/* beware of wrapping */
if(MAX_TICKS - t < i) {
while(u16AHI_TimerReadCount(CLOCK_TIMER) < MAX_TICKS && u16AHI_TimerReadCount(CLOCK_TIMER) != 0) ;
i -= MAX_TICKS - t;
t = 0;
}
while(u16AHI_TimerReadCount(CLOCK_TIMER) - t < i) {
uint32_t end = clock() + dt * 128;
while(CLOCK_LT(clock(), end)) {
watchdog_periodic();
}
}
@ -218,33 +240,63 @@ clock_delay(unsigned int i)
void
clock_wait(clock_time_t t)
{
clock_time_t start;
start = clock_time();
while(clock_time() - start < (clock_time_t)t) {
clock_time_t end = clock_time() + t;
while(CLOCK_LT(clock_time(), end)) {
watchdog_periodic();
}
}
/*---------------------------------------------------------------------------*/
void
clock_set_seconds(unsigned long sec)
{
seconds = sec;
}
/*---------------------------------------------------------------------------*/
unsigned long
clock_seconds(void)
{
unsigned long t1, t2;
do {
t1 = seconds;
t2 = seconds;
} while(t1 != t2);
return t1;
return clock_time() / CLOCK_SECOND;
}
/*---------------------------------------------------------------------------*/
rtimer_clock_t
clock_counter(void)
clock_time_t
clock_arch_time_to_etimer(void)
{
return rtimer_arch_now();
clock_time_t time_to_etimer;
if(etimer_pending()) {
time_to_etimer = etimer_next_expiration_time() - clock_time();
if(time_to_etimer < 0) {
time_to_etimer = 0;
}
} else {
/* no active etimers */
time_to_etimer = (clock_time_t)-1;
}
return time_to_etimer;
}
/*---------------------------------------------------------------------------*/
void
clock_arch_schedule_interrupt(clock_time_t time_to_etimer, rtimer_clock_t ticks_to_rtimer)
{
if(time_to_etimer > CLOCK_MAX_SCHEDULABLE_TICKS) {
time_to_etimer = CLOCK_MAX_SCHEDULABLE_TICKS;
}
time_to_etimer *= CLOCK_INTERVAL;
if(ticks_to_rtimer != (rtimer_clock_t)-1) {
/* if the next rtimer is close enough to the etimer... */
rtimer_clock_t ticks_to_etimer = time_to_etimer * (1 << CLOCK_PRESCALE);
#if RTIMER_USE_32KHZ
ticks_to_rtimer = (uint64_t)ticks_to_rtimer * (F_CPU / 2) / RTIMER_SECOND;
#endif
if(!CLOCK_LT(ticks_to_rtimer, ticks_to_etimer)
&& CLOCK_LT(ticks_to_rtimer, ticks_to_etimer + CLOCK_RTIMER_GUARD_TIME)) {
/* ..then schedule the etimer after the rtimer */
time_to_etimer += 2;
}
}
/* interrupt will not be generated if 0 is passed as the parameter */
if(time_to_etimer == 0) {
time_to_etimer = 1;
}
vAHI_TimerStartSingleShot(CLOCK_TIMER, 0, time_to_etimer);
}
/*---------------------------------------------------------------------------*/

View File

@ -119,8 +119,6 @@ void vMMAC_SetChannelAndPower(uint8 u8Channel, int8 i8power);
#define MICROMAC_CONF_AUTOACK 1
#endif /* MICROMAC_CONF_AUTOACK */
#define RADIO_TO_RTIMER(X) ((rtimer_clock_t)((X) << (int32_t)8L))
/* Set radio always on for now because this is what Contiki MAC layers
* expect. */
#ifndef MICROMAC_CONF_ALWAYS_ON
@ -151,11 +149,11 @@ static uint8_t autoack_enabled = MICROMAC_CONF_AUTOACK;
static uint8_t send_on_cca = 0;
/* Current radio channel */
static int current_channel;
static int current_channel = MICROMAC_CONF_CHANNEL;
/* Current set point tx power
Actual tx power may be different. Use get_txpower() for actual power */
static int current_tx_power;
static int current_tx_power = MICROMAC_CONF_TX_POWER;
/* an integer between 0 and 255, used only with cca() */
static uint8_t cca_thershold = MICROMAC_CONF_CCA_THR;
@ -278,44 +276,22 @@ frame802154_has_panid(frame802154_fcf_t *fcf, int *has_src_pan_id, int *has_dest
static rtimer_clock_t
get_packet_timestamp(void)
{
/* Wait for an edge */
uint32_t t = u32MMAC_GetTime();
while(u32MMAC_GetTime() == t);
/* Save SFD timestamp, converted from radio timer to RTIMER */
last_packet_timestamp = RTIMER_NOW() -
RADIO_TO_RTIMER((uint32_t)(u32MMAC_GetTime() - u32MMAC_GetRxTime()));
RADIO_TO_RTIMER((uint32_t)(u32MMAC_GetTime() - (u32MMAC_GetRxTime() - 1)));
/* The remaining measured error is typically in range 0..16 usec.
* Center it around zero, in the -8..+8 usec range. */
last_packet_timestamp -= US_TO_RTIMERTICKS(8);
return last_packet_timestamp;
}
/*---------------------------------------------------------------------------*/
static int
init(void)
init_software(void)
{
int put_index;
tsExtAddr node_long_address;
uint16_t node_short_address;
tx_in_progress = 0;
u32JPT_Init();
vMMAC_Enable();
/* Enable/disable interrupts */
if(poll_mode) {
vMMAC_EnableInterrupts(NULL);
vMMAC_ConfigureInterruptSources(0);
} else {
vMMAC_EnableInterrupts(&radio_interrupt_handler);
} vMMAC_ConfigureRadio();
set_channel(MICROMAC_CONF_CHANNEL);
set_txpower(MICROMAC_CONF_TX_POWER);
vMMAC_GetMacAddress(&node_long_address);
/* Short addresses are disabled by default */
node_short_address = (uint16_t)node_long_address.u32L;
vMMAC_SetRxAddress(frame802154_get_pan_id(), node_short_address, &node_long_address);
/* Disable hardware backoff */
vMMAC_SetTxParameters(1, 0, 0, 0);
vMMAC_SetCutOffTimer(0, FALSE);
/* Initialize ring buffer and first input packet pointer */
ringbufindex_init(&input_ringbuf, MIRCOMAC_CONF_BUF_NUM);
/* get pointer to next input slot */
@ -332,6 +308,42 @@ init(void)
process_start(&micromac_radio_process, NULL);
return 1;
}
/*---------------------------------------------------------------------------*/
static int
init(void)
{
int ret = 1;
tsExtAddr node_long_address;
uint16_t node_short_address;
static uint8_t is_initialized;
tx_in_progress = 0;
u32JPT_Init();
vMMAC_Enable();
/* Enable/disable interrupts */
if(poll_mode) {
vMMAC_EnableInterrupts(NULL);
vMMAC_ConfigureInterruptSources(0);
} else {
vMMAC_EnableInterrupts(&radio_interrupt_handler);
}
vMMAC_ConfigureRadio();
set_channel(current_channel);
set_txpower(current_tx_power);
vMMAC_GetMacAddress(&node_long_address);
/* Short addresses are disabled by default */
node_short_address = (uint16_t)node_long_address.u32L;
vMMAC_SetRxAddress(frame802154_get_pan_id(), node_short_address, &node_long_address);
/* Disable hardware backoff */
vMMAC_SetTxParameters(1, 0, 0, 0);
vMMAC_SetCutOffTimer(0, FALSE);
#if RADIO_TEST_MODE == RADIO_TEST_MODE_HIGH_PWR
/* Enable high power mode.
* In this mode DIO2 goes high during RX
@ -348,7 +360,12 @@ init(void)
u32REG_SysRead(REG_SYS_PWR_CTRL) | (1UL << 26UL));
#endif /* TEST_MODE */
return 1;
if(!is_initialized) {
is_initialized = 1;
ret = init_software();
}
return ret;
}
/*---------------------------------------------------------------------------*/
static int

View File

@ -0,0 +1,183 @@
/*
* Copyright (c) 2014, SICS Swedish ICT.
* 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 Institute 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 INSTITUTE 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 INSTITUTE 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.
*
* This file is part of the Contiki operating system.
*
*/
/**
* \file
* RTIMER for NXP jn516x: 32 kHz mode
* \author
* Atis Elsts <atis.elsts@sics.se>
*/
#include "sys/rtimer.h"
#include "sys/clock.h"
#include <AppHardwareApi.h>
#include <PeripheralRegs.h>
#include <MicroSpecific.h>
#include "dev/watchdog.h"
#include "sys/energest.h"
#include "sys/process.h"
#if RTIMER_USE_32KHZ
#define DEBUG 0
#if DEBUG
#include <stdio.h>
#define PRINTF(...) printf(__VA_ARGS__)
#else
#define PRINTF(...)
#endif
#define RTIMER_TIMER_ISR_DEV E_AHI_DEVICE_SYSCTRL
/* 1.5 days wraparound time */
#define MAX_VALUE 0xFFFFFFFF
/* make this small to more easily detect wraparound bugs */
#define START_VALUE (60 * RTIMER_ARCH_SECOND)
#define WRAPAROUND_VALUE ((uint64_t)0x1FFFFFFFFFF)
static volatile rtimer_clock_t scheduled_time;
static volatile uint8_t has_next;
/*---------------------------------------------------------------------------*/
static void
timerISR(uint32 u32Device, uint32 u32ItemBitmap)
{
PRINTF("\ntimer isr %u %u\n", u32Device, u32ItemBitmap);
if(u32Device != RTIMER_TIMER_ISR_DEV) {
return;
}
ENERGEST_ON(ENERGEST_TYPE_IRQ);
if(u32ItemBitmap & TICK_TIMER_MASK) {
/* 32-bit overflow happened; restart the timer */
uint32_t ticks_late = WRAPAROUND_VALUE - u64AHI_WakeTimerReadLarge(TICK_TIMER);
PRINTF("\nrtimer oflw, missed ticks %u\n", ticks_late);
vAHI_WakeTimerStartLarge(TICK_TIMER, MAX_VALUE - ticks_late);
}
if(u32ItemBitmap & WAKEUP_TIMER_MASK) {
PRINTF("\nrtimer fire @ %u\n", rtimer_arch_now());
/* Compare with the current time, as after sleep there is
* a fake interrupt generated 10ms earlier to wake up & reinitialize
* the system before the actual rtimer fires.
*/
rtimer_clock_t now = rtimer_arch_now();
if(RTIMER_CLOCK_LT(now + 1, scheduled_time)) {
vAHI_WakeTimerEnable(WAKEUP_TIMER, TRUE);
vAHI_WakeTimerStartLarge(WAKEUP_TIMER, scheduled_time - now);
} else {
has_next = 0;
watchdog_start();
rtimer_run_next();
process_nevents();
}
}
ENERGEST_OFF(ENERGEST_TYPE_IRQ);
}
/*---------------------------------------------------------------------------*/
void
rtimer_arch_init(void)
{
/* Initialise tick timer to run continuously */
vAHI_TickTimerIntEnable(0);
vAHI_TickTimerConfigure(E_AHI_TICK_TIMER_DISABLE);
vAHI_TickTimerWrite(0);
vAHI_TickTimerConfigure(E_AHI_TICK_TIMER_CONT);
vAHI_SysCtrlRegisterCallback(timerISR);
/* set the highest priority for the rtimer interrupt */
vAHI_InterruptSetPriority(MICRO_ISR_MASK_SYSCTRL, 15);
/* enable interrupt on a rtimer */
vAHI_WakeTimerEnable(WAKEUP_TIMER, TRUE);
/* enable interrupt on 32-bit overflow */
vAHI_WakeTimerEnable(TICK_TIMER, TRUE);
/* count down from START_VALUE */
vAHI_WakeTimerStartLarge(TICK_TIMER, START_VALUE);
(void)u32AHI_Init();
}
/*---------------------------------------------------------------------------*/
void
rtimer_arch_reinit(rtimer_clock_t sleep_start, rtimer_clock_t sleep_ticks)
{
uint64_t t;
uint32_t wakeup_time = sleep_start + (uint64_t)sleep_ticks * (F_CPU / 2) / RTIMER_SECOND;
/* Initialise tick timer to run continuously */
vAHI_TickTimerConfigure(E_AHI_TICK_TIMER_DISABLE);
vAHI_TickTimerIntEnable(0);
WAIT_FOR_EDGE(t);
vAHI_TickTimerWrite(wakeup_time);
vAHI_TickTimerConfigure(E_AHI_TICK_TIMER_CONT);
/* call pending interrupts */
(void)u32AHI_Init();
if(has_next) {
/* reschedule the timer */
rtimer_arch_schedule(scheduled_time);
}
}
/*---------------------------------------------------------------------------*/
rtimer_clock_t
rtimer_arch_now(void)
{
return START_VALUE - (rtimer_clock_t)u64AHI_WakeTimerReadLarge(TICK_TIMER);
}
/*---------------------------------------------------------------------------*/
void
rtimer_arch_schedule(rtimer_clock_t t)
{
PRINTF("rtimer_arch_schedule time %lu\n", t);
vAHI_WakeTimerEnable(WAKEUP_TIMER, TRUE);
vAHI_WakeTimerStartLarge(WAKEUP_TIMER, t - rtimer_arch_now());
scheduled_time = t;
has_next = 1;
}
/*---------------------------------------------------------------------------*/
rtimer_clock_t
rtimer_arch_time_to_rtimer(void)
{
rtimer_clock_t now = RTIMER_NOW();
if(has_next) {
return scheduled_time >= now ? scheduled_time - now : 0;
}
/* if no wakeup is scheduled yet return maximum time */
return (rtimer_clock_t)-1;
}
/*---------------------------------------------------------------------------*/
#endif /* RTIMER_USE_32KHZ */

View File

@ -35,17 +35,19 @@
* RTIMER for NXP jn516x
* \author
* Beshr Al Nahas <beshr@sics.se>
* Atis Elsts <atis.elsts@sics.se>
*/
#include "sys/rtimer.h"
#include "sys/clock.h"
#include "sys/process.h"
#include <AppHardwareApi.h>
#include <PeripheralRegs.h>
#include <MicroSpecific.h>
#include "dev/watchdog.h"
#include "sys/energest.h"
#include "sys/process.h"
#define RTIMER_TIMER_ISR_DEV E_AHI_DEVICE_TICK_TIMER
#if !RTIMER_USE_32KHZ
#define DEBUG 0
#if DEBUG
@ -55,16 +57,20 @@
#define PRINTF(...)
#endif
static volatile uint32_t compare_time;
static volatile uint32_t last_expired_time;
#define RTIMER_TIMER_ISR_DEV E_AHI_DEVICE_TICK_TIMER
static volatile rtimer_clock_t scheduled_time;
static volatile uint8_t has_next;
void
rtimer_arch_run_next(uint32 u32DeviceId, uint32 u32ItemBitmap)
{
uint32_t delta, temp;
uint32_t delta;
if(u32DeviceId != RTIMER_TIMER_ISR_DEV) {
return;
}
ENERGEST_ON(ENERGEST_TYPE_IRQ);
vAHI_TickTimerIntPendClr();
vAHI_TickTimerIntEnable(0);
@ -72,27 +78,17 @@ rtimer_arch_run_next(uint32 u32DeviceId, uint32 u32ItemBitmap)
* compare register is only 28bits wide so make sure the upper 4bits match
* the set compare point
*/
delta = u32AHI_TickTimerRead() - compare_time;
if(0 == (delta >> 28)) {
/* compare_time might change after executing rtimer_run_next()
* as some process might schedule the timer
*/
temp = compare_time;
delta = u32AHI_TickTimerRead() - scheduled_time;
if(delta >> 28 == 0) {
/* run scheduled */
has_next = 0;
watchdog_start();
rtimer_run_next();
if(process_nevents() > 0) {
/* TODO exit low-power mode */
}
watchdog_stop();
last_expired_time = temp;
process_nevents();
} else {
/* No match. Schedule again. */
vAHI_TickTimerIntEnable(1);
vAHI_TickTimerInterval(compare_time);
vAHI_TickTimerInterval(scheduled_time);
}
ENERGEST_OFF(ENERGEST_TYPE_IRQ);
}
@ -101,12 +97,43 @@ void
rtimer_arch_init(void)
{
/* Initialise tick timer to run continuously */
vAHI_TickTimerIntEnable(0);
vAHI_TickTimerConfigure(E_AHI_TICK_TIMER_DISABLE);
last_expired_time = compare_time = 0;
vAHI_TickTimerWrite(0);
vAHI_TickTimerIntEnable(0);
vAHI_TickTimerRegisterCallback(rtimer_arch_run_next);
vAHI_TickTimerWrite(0);
vAHI_TickTimerConfigure(E_AHI_TICK_TIMER_CONT);
/* enable wakeup timers, but keep interrupts disabled */
vAHI_WakeTimerEnable(WAKEUP_TIMER, FALSE);
vAHI_WakeTimerEnable(TICK_TIMER, FALSE);
/* count down from zero (2, as values 0 and 1 must not be used) */
vAHI_WakeTimerStartLarge(TICK_TIMER, 2);
(void)u32AHI_Init();
}
/*---------------------------------------------------------------------------*/
void
rtimer_arch_reinit(rtimer_clock_t sleep_start, rtimer_clock_t sleep_ticks)
{
uint64_t t;
/* Initialise tick timer to run continuously */
vAHI_TickTimerConfigure(E_AHI_TICK_TIMER_DISABLE);
vAHI_TickTimerIntEnable(0);
/* set the highest priority for the rtimer interrupt */
vAHI_InterruptSetPriority(MICRO_ISR_MASK_TICK_TMR, 15);
vAHI_TickTimerRegisterCallback(rtimer_arch_run_next);
WAIT_FOR_EDGE(t);
vAHI_TickTimerWrite(sleep_start + sleep_ticks);
vAHI_TickTimerConfigure(E_AHI_TICK_TIMER_CONT);
/* call pending interrupts */
u32AHI_Init();
if(has_next) {
vAHI_TickTimerIntPendClr();
vAHI_TickTimerIntEnable(1);
vAHI_TickTimerInterval(scheduled_time);
}
}
/*---------------------------------------------------------------------------*/
rtimer_clock_t
@ -122,18 +149,19 @@ rtimer_arch_schedule(rtimer_clock_t t)
vAHI_TickTimerIntPendClr();
vAHI_TickTimerIntEnable(1);
vAHI_TickTimerInterval(t);
compare_time = t;
has_next = 1;
scheduled_time = t;
}
/*---------------------------------------------------------------------------*/
rtimer_clock_t
rtimer_arch_get_time_until_next_wakeup(void)
rtimer_arch_time_to_rtimer(void)
{
rtimer_clock_t now = RTIMER_NOW();
rtimer_clock_t next_wakeup = compare_time;
if(bAHI_TickTimerIntStatus()) {
return next_wakeup >= now ? next_wakeup - now : 0;
/* if no wakeup is scheduled yet return maximum time */
if(has_next) {
return scheduled_time >= now ? scheduled_time - now : 0;
}
/* if no wakeup is scheduled yet return maximum time */
return (rtimer_clock_t)-1;
}
/*---------------------------------------------------------------------------*/
#endif /* !RTIMER_USE_32KHZ */

View File

@ -35,6 +35,7 @@
* Header file for NXP jn516x-specific rtimer code
* \author
* Beshr Al Nahas <beshr@sics.se>
* Atis Elsts <atis.elsts@sics.se>
*/
#ifndef RTIMER_ARCH_H_
@ -43,18 +44,75 @@
#include "sys/rtimer.h"
#ifdef RTIMER_CONF_SECOND
#define RTIMER_ARCH_SECOND RTIMER_CONF_SECOND
# define RTIMER_ARCH_SECOND RTIMER_CONF_SECOND
#else
#if RTIMER_USE_32KHZ
# if JN516X_EXTERNAL_CRYSTAL_OSCILLATOR
# define RTIMER_ARCH_SECOND 32768
# else
# define RTIMER_ARCH_SECOND 32000
#endif
#else
/* 32MHz CPU clock => 16MHz timer */
#define RTIMER_ARCH_SECOND (F_CPU / 2)
# define RTIMER_ARCH_SECOND (F_CPU / 2)
#endif
#endif
#define US_TO_RTIMERTICKS(D) ((int64_t)(D) << 4)
#define RTIMERTICKS_TO_US(T) ((int64_t)(T) >> 4)
#define RTIMERTICKS_TO_US_64(T) RTIMERTICKS_TO_US(T)
#if RTIMER_USE_32KHZ
#define US_TO_RTIMERTICKS(US) ((US) >= 0 ? \
(((int32_t)(US) * (RTIMER_ARCH_SECOND) + 500000) / 1000000L) : \
((int32_t)(US) * (RTIMER_ARCH_SECOND) - 500000) / 1000000L)
#define RTIMERTICKS_TO_US(T) ((T) >= 0 ? \
(((int32_t)(T) * 1000000L + ((RTIMER_ARCH_SECOND) / 2)) / (RTIMER_ARCH_SECOND)) : \
((int32_t)(T) * 1000000L - ((RTIMER_ARCH_SECOND) / 2)) / (RTIMER_ARCH_SECOND))
/* A 64-bit version because the 32-bit one cannot handle T >= 4295 ticks.
Intended only for positive values of T. */
#define RTIMERTICKS_TO_US_64(T) ((uint32_t)(((uint64_t)(T) * 1000000 + ((RTIMER_ARCH_SECOND) / 2)) / (RTIMER_ARCH_SECOND)))
#else
#define US_TO_RTIMERTICKS(D) ((int64_t)(D) << 4)
#define RTIMERTICKS_TO_US(T) ((int64_t)(T) >> 4)
#define RTIMERTICKS_TO_US_64(T) RTIMERTICKS_TO_US(T)
#endif
rtimer_clock_t rtimer_arch_now(void);
rtimer_clock_t rtimer_arch_get_time_until_next_wakeup(void);
rtimer_clock_t rtimer_arch_time_to_rtimer(void);
void rtimer_arch_reinit(rtimer_clock_t sleep_start, rtimer_clock_t wakeup_time);
void clock_arch_init(int is_reinitialization);
void clock_arch_calibrate(void);
void clock_arch_reinit(void);
void clock_arch_schedule_interrupt(clock_time_t time_to_etimer, rtimer_clock_t ticks_to_rtimer);
clock_t clock_arch_time_to_etimer(void);
/* Use 20 ms: enough for TSCH with the default schedule to sleep */
#define JN516X_MIN_SLEEP_TIME (RTIMER_SECOND / 50)
/* 1 second by default: arbitrary picked value which could be increased */
#define JN516X_MAX_SLEEP_TIME RTIMER_SECOND
/* Assume conservative 10 ms maximal system wakeup time */
#define JN516X_SLEEP_GUARD_TIME (RTIMER_ARCH_SECOND / 100)
#define WAKEUP_TIMER E_AHI_WAKE_TIMER_0
#define WAKEUP_TIMER_MASK E_AHI_SYSCTRL_WK0_MASK
#define TICK_TIMER E_AHI_WAKE_TIMER_1
#define TICK_TIMER_MASK E_AHI_SYSCTRL_WK1_MASK
#define WAIT_FOR_EDGE(edge_t) do { \
uint64_t start_t = u64AHI_WakeTimerReadLarge(TICK_TIMER); \
do { \
edge_t = u64AHI_WakeTimerReadLarge(TICK_TIMER); \
} while(edge_t == start_t); \
} while(0)
#endif /* RTIMER_ARCH_H_ */

View File

@ -39,6 +39,8 @@
#include <jendefs.h>
#include "contiki-conf.h"
#define UART_EXTRAS 1
void uart_driver_init(uint8_t uart_dev, uint8_t br, uint8_t * txbuf_data, uint16_t txbuf_size, uint8_t * rxbuf_data, uint16_t rxbuf_size, int (*uart_input_function)(unsigned char c));
void uart_driver_write_buffered(uint8_t uart_dev, uint8_t ch);
void uart_driver_write_with_deadline(uint8_t uart_dev, uint8_t c);

View File

@ -44,6 +44,8 @@
/* Delay between GO signal and start listening
* Measured 104us: between GO signal and start listening */
#define RADIO_DELAY_BEFORE_RX ((unsigned)US_TO_RTIMERTICKS(104))
/* Delay between the SFD finishes arriving and it is detected in software */
#define RADIO_DELAY_BEFORE_DETECT ((unsigned)US_TO_RTIMERTICKS(14))
/* Micromac configuration */
@ -59,9 +61,57 @@
#define MICROMAC_CONF_CHANNEL RF_CHANNEL
#endif
/* Timer conversion
* RTIMER 16M = 256 * 62500(RADIO) == 2^8 * 62500 */
#define RADIO_TO_RTIMER(X) ((rtimer_clock_t)((X) << (int32_t)8L))
/* 32kHz or 16MHz rtimers? */
#ifdef RTIMER_CONF_USE_32KHZ
#define RTIMER_USE_32KHZ RTIMER_CONF_USE_32KHZ
#else
#define RTIMER_USE_32KHZ 0
#endif
/* Put the device in a sleep mode in idle periods?
* If RTIMER_USE_32KHZ is set, the device runs all the time on the 32 kHz oscillator.
* If RTIMER_USE_32KHZ is not set, the device runs on the 32 kHz oscillator during sleep,
* and switches back to the 32 MHz oscillator (16 MHz rtimer) at wakeup.
* */
#ifdef JN516X_SLEEP_CONF_ENABLED
#define JN516X_SLEEP_ENABLED JN516X_SLEEP_CONF_ENABLED
#else
#define JN516X_SLEEP_ENABLED 0
#endif
/* Enable this to get the 32.768kHz oscillator */
#ifndef JN516X_EXTERNAL_CRYSTAL_OSCILLATOR
#define JN516X_EXTERNAL_CRYSTAL_OSCILLATOR (RTIMER_USE_32KHZ || JN516X_SLEEP_ENABLED)
#endif /* JN516X_EXTERNAL_CRYSTAL_OSCILLATOR */
/* Core rtimer.h defaults to 16 bit timer unless RTIMER_CLOCK_LT is defined */
typedef uint32_t rtimer_clock_t;
#define RTIMER_CLOCK_LT(a, b) ((int32_t)((a) - (b)) < 0)
/* 8ms timer tick */
#define CLOCK_CONF_SECOND 125
#if JN516X_EXTERNAL_CRYSTAL_OSCILLATOR
#define JN516X_XOSC_SECOND 32768
#else
#define JN516X_XOSC_SECOND 32000
#endif
/* Timer conversion*/
#if RTIMER_USE_32KHZ
#define RADIO_TO_RTIMER(X) ((X) * (JN516X_XOSC_SECOND) / 62500)
#else
/* RTIMER 16M = 256 * 62500(RADIO) == 2^8 * 62500 */
#define RADIO_TO_RTIMER(X) ((rtimer_clock_t)((X) << (int32_t)8L))
#endif
/* If the timer base a binary 32kHz clock, compensate for this base drift */
#if RTIMER_USE_32KHZ && JN516X_EXTERNAL_CRYSTAL_OSCILLATOR
/* Drift calculated using this formula:
* ((US_TO_TICKS(10000) * 100) - RTIMER_SECOND) * 1e6 = 976.5625 ppm
*/
#define TSCH_CONF_BASE_DRIFT_PPM -977
#endif
#define DR_11744_DIO2 12
#define DR_11744_DIO3 13
@ -70,6 +120,13 @@
#define DR_11744_DIO6 16
#define DR_11744_DIO7 17
/* Enable power amplifier of JN5168 M05 and M06 modules */
#if defined(JN5168_M05) || defined(JN5168_M06)
#define RADIO_TEST_MODE RADIO_TEST_MODE_HIGH_PWR
#else
#define RADIO_TEST_MODE RADIO_TEST_MODE_DISABLED
#endif
#define TSCH_DEBUG 0
#if TSCH_DEBUG
@ -183,14 +240,10 @@ typedef long long int64_t;
typedef uint16_t uip_stats_t;
typedef uint32_t clock_time_t;
/* Core rtimer.h defaults to 16 bit timer unless RTIMER_CLOCK_LT is defined */
typedef uint32_t rtimer_clock_t;
#define RTIMER_CLOCK_LT(a, b) ((int32_t)((a) - (b)) < 0)
/* 10ms timer tick */
#define CLOCK_CONF_SECOND 100
/* Shall we calibrate the DCO periodically? */
#ifndef DCOSYNCH_CONF_ENABLED
#define DCOSYNCH_CONF_ENABLED 1
#endif
/* How often shall we attempt to calibrate DCO?
* PS: It should be calibrated upon temperature changes,
@ -223,11 +276,6 @@ typedef uint32_t rtimer_clock_t;
#define SLIP_BRIDGE_CONF_NO_PUTCHAR 1
#endif /* SLIP_BRIDGE_CONF_NO_PUTCHAR */
/* Enable this to get the 32.768kHz oscillator */
#ifndef USE_EXTERNAL_OSCILLATOR
#define USE_EXTERNAL_OSCILLATOR 0
#endif /* USE_EXTERNAL_OSCILLATOR */
/* Extension of LED definitions from leds.h for various JN516x dev boards
JN516x Dongle:
LEDS_RED Red LED on dongle