[nrf][clock] use nrfx lib clock driver

Using Nordic's nrfx driver for the clock control peripheral since
it address a handful of errata and abstracts some differences
in the nrf52 family of parts.
This commit is contained in:
Eric Holland
2020-10-06 10:08:33 -04:00
parent 7068fb63cb
commit d1bad2e683
10 changed files with 156 additions and 15 deletions

View File

@@ -3,11 +3,12 @@ LOCAL_DIR := $(GET_LOCAL_DIR)
MODULE := $(LOCAL_DIR)
MODULE_SRCS := \
$(LOCAL_DIR)/drivers/src/nrfx_clock.c \
$(LOCAL_DIR)/drivers/src/nrfx_twi.c \
$(LOCAL_DIR)/drivers/src/nrfx_twi_twim.c \
$(LOCAL_DIR)/drivers/src/nrfx_twim.c \
$(LOCAL_DIR)/drivers/src/nrfx_usbd.c \
$(LOCAL_DIR)/mdk/system_nrf52.c \
$(LOCAL_DIR)/mdk/system_nrf52840.c \
$(LOCAL_DIR)/soc/nrfx_atomic.c \
# The nrfx library doesn't follow the typical lk include directory layout

91
platform/nrf52xxx/clock.c Normal file
View File

@@ -0,0 +1,91 @@
/*
* Copyright (c) 2020 Eric Holland
*
* Use of this source code is governed by a MIT-style
* license that can be found in the LICENSE file or at
* https://opensource.org/licenses/MIT
*/
#include <sys/types.h>
#include <lk/err.h>
#include <kernel/event.h>
#include <nrfx.h>
#include <nrfx_clock.h>
#include <hal/nrf_clock.h>
#include <platform/clock.h>
event_t hf_clk_evt = EVENT_INITIAL_VALUE(hf_clk_evt, false, 0);
event_t lf_clk_evt = EVENT_INITIAL_VALUE(lf_clk_evt, false, 0);
void nrf52_POWER_CLOCK_IRQ(void) {
arm_cm_irq_entry();
nrfx_clock_irq_handler();
arm_cm_irq_exit(true);
}
// Handler runs in interrupt context
void nrf52_clock_handler(nrfx_clock_evt_type_t event) {
switch (event) {
case NRFX_CLOCK_EVT_HFCLK_STARTED :
event_signal(&hf_clk_evt, false);
break;
case NRFX_CLOCK_EVT_LFCLK_STARTED :
event_signal(&lf_clk_evt, false);
break;
default:
break;
}
}
status_t nrf52_clock_init(void) {
status_t status = nrfx_clock_init(nrf52_clock_handler);
if (status == NO_ERROR) {
nrfx_clock_enable();
}
return status;
}
status_t nrf52_clock_hf_use_xtal_source(void) {
// Check if already running on hfclk xtal
if (nrfx_clock_hfclk_is_running()) {
return NO_ERROR;
}
event_unsignal(&hf_clk_evt);
nrfx_clock_hfclk_start();
if (event_wait_timeout(&hf_clk_evt, 100) != NO_ERROR) {
dprintf(CRITICAL, "Timeout waiting for hf source\n");
return ERR_TIMED_OUT;
}
return NO_ERROR;
}
// Switch to using the internal 64MHz oscillator for HF clock
void nrf52_clock_hf_use_internal_source(void) {
//The clock controller will automatically switch to the internal
// oscillator as the source when the external xtal is stopped.
// this nrfx function is poorly named as it does not stop the hf clock
// but only stops the external xtal oscillator.
nrfx_clock_hfclk_stop();
}
status_t nrf52_clock_lfclk_enable(nrf_clock_lfclk_t src) {
if (nrfx_clock_lfclk_is_running()) {
nrf_clock_lfclk_t current_src = nrf_clock_lf_actv_src_get(NRF_CLOCK);
if (current_src == src) {
//Already running on the requested source, do nothing.
return NO_ERROR;
}
// If we make it here, it is running, but not right source, so shut it down to change
nrfx_clock_lfclk_stop();
}
nrf_clock_lf_src_set(NRF_CLOCK, src);
event_unsignal(&lf_clk_evt);
nrfx_clock_lfclk_start();
if (event_wait_timeout(&lf_clk_evt, 100) != NO_ERROR) {
dprintf(CRITICAL, "Timeout waiting for lf clock start\n");
return ERR_TIMED_OUT;
}
return NO_ERROR;
}

View File

@@ -0,0 +1,21 @@
/*
* Copyright (c) 2020 Eric Holland
*
* Use of this source code is governed by a MIT-style
* license that can be found in the LICENSE file or at
* https://opensource.org/licenses/MIT
*/
#pragma once
#include <nrfx.h>
#include <nrfx_clock.h>
#include <hal/nrf_clock.h>
// Must be called before other functions can be used.
status_t nrf52_clock_init(void);
status_t nrf52_clock_hf_use_xtal_source(void);
void nrf52_clock_hf_use_internal_source(void);
status_t nrf52_clock_lfclk_enable(nrf_clock_lfclk_t src);

View File

@@ -11,17 +11,29 @@
#include <dev/i2c.h>
#include <dev/uart.h>
#include <platform.h>
#include <platform/init.h>
#include <platform/clock.h>
#include <nrfx.h>
#include <mdk/system_nrf52.h>
#include <nrfx_clock.h>
void platform_early_init(void) {
// Crank up the clock before initing timers.
SystemInit();
// Initialize the clock control peripheral
nrf52_clock_init();
arm_cm_systick_init(32768);
}
void platform_init(void) {
dprintf(SPEW, "Nordic nrf52xxx platform for lk...\n");
char *variant = (char *)&NRF_FICR->FICR_INFO.VARIANT;
dprintf(SPEW, "Part Number - %x-%c%c%c%c\n", NRF_FICR->FICR_INFO.PART,
variant[3], variant[2], variant[1], variant[0]);
dprintf(SPEW, "\tRam: %dk\n", NRF_FICR->FICR_INFO.RAM);
dprintf(SPEW, "\tFlash: %d pages of %d bytes each (%dk bytes total)\n", \
NRF_FICR->CODESIZE, NRF_FICR->CODEPAGESIZE, \
(NRF_FICR->CODESIZE * NRF_FICR->CODEPAGESIZE)>>10);
@@ -32,6 +44,7 @@ void platform_init(void) {
(NRF_FICR->DEVICEADDR[0] >> 16) & 0xFF, \
(NRF_FICR->DEVICEADDR[0] >> 8) & 0xFF, \
(NRF_FICR->DEVICEADDR[0] >> 0) & 0xFF);
// Note: i2c_init will only instantiate an i2c device if proper defines
// are set. See comments at top of i2c_master.c for more info.
i2c_init();

View File

@@ -37,10 +37,13 @@ GLOBAL_DEFINES += \
MEMSIZE=$(MEMSIZE)
# Other important defines
#GLOBAL_DEFINES += \
GLOBAL_DEFINES += \
NRFX_CLOCK_ENABLED=1 \
# NRFX_ENABLE_LOGGING=1 \
MODULE_SRCS += \
$(LOCAL_DIR)/clock.c \
$(LOCAL_DIR)/i2c_master.c \
$(LOCAL_DIR)/init.c \
$(LOCAL_DIR)/debug.c \

View File

@@ -10,8 +10,12 @@
#include <platform.h>
#include <nrfx.h>
#include <platform/timer.h>
#include <platform/clock.h>
#include <nrfx_clock.h>
#include <sys/types.h>
// TODO - integrate nrfx rtc driver instead of direct register manipulation here.
//base counter is total number of clock cycles elapsed
static volatile uint64_t base_counter = 0;
@@ -27,15 +31,12 @@ typedef enum handler_return (*platform_timer_callback)(void *arg, lk_time_t now)
status_t platform_set_periodic_timer(platform_timer_callback callback, void *arg, lk_time_t interval) {
ASSERT(clock_rate > 0);
ASSERT(nrfx_clock_lfclk_is_running());
cb = callback;
cb_args = arg;
cycles_per_tick = clock_rate * interval / 1000 ;
NRF_CLOCK->LFCLKSRC = CLOCK_LFCLKSRC_SRC_Xtal << CLOCK_LFCLKSRC_SRC_Pos;
NRF_CLOCK->TASKS_LFCLKSTART = 1;
NRF_RTC1->CC[0] = 0x00ffffff & (base_counter + cycles_per_tick);
NRF_RTC1->PRESCALER = 0;
@@ -95,6 +96,9 @@ void nrf52_RTC1_IRQ(void) {
}
void arm_cm_systick_init(uint32_t hz) {
ASSERT(hz == 32768);
clock_rate = hz;
//Enable the LF xtal oscillator
nrf52_clock_lfclk_enable(NRF_CLOCK_LFCLK_Xtal);
}

View File

@@ -8,9 +8,6 @@
#include <lk/debug.h>
#include <lk/compiler.h>
#include <arch/arm/cm.h>
#include <lib/cbuf.h>
#include <platform/nrf52.h>
#include <target/debugconfig.h>
/* un-overridden irq handler */
void nrf52_dummy_irq(void) {

View File

@@ -9,9 +9,20 @@
#define __TARGET_GPIOCONFIG_H
#define GPIO_LED1 13
#define LED1_ON gpio_set(GPIO_LED1,0)
#define LED1_OFF gpio_set(GPIO_LED1,1)
#define GPIO_LED2 14
#define LED2_ON gpio_set(GPIO_LED2,0)
#define LED2_OFF gpio_set(GPIO_LED2,1)
#define GPIO_LED3 15
#define LED3_ON gpio_set(GPIO_LED3,0)
#define LED3_OFF gpio_set(GPIO_LED3,1)
#define GPIO_LED4 16
#define LED4_ON gpio_set(GPIO_LED4,0)
#define LED4_OFF gpio_set(GPIO_LED4,1)
#define UART0_TX_PIN 6
#define UART0_RX_PIN 8

View File

@@ -11,7 +11,7 @@
#include <lk/compiler.h>
#include <nrfx_usbd.h>
#include <dev/gpio.h>
#include <platform/nrf52.h>
#include <platform/init.h>
#include <target/gpioconfig.h>
void target_early_init(void) {
@@ -20,10 +20,10 @@ void target_early_init(void) {
gpio_config(GPIO_LED3, GPIO_OUTPUT);
gpio_config(GPIO_LED4, GPIO_OUTPUT);
gpio_set(GPIO_LED1,0);
gpio_set(GPIO_LED2,0);
gpio_set(GPIO_LED3,0);
gpio_set(GPIO_LED4,0);
LED1_OFF;
LED2_OFF;
LED3_OFF;
LED4_OFF;
nrf52_debug_early_init();
}