218 lines
5.9 KiB
C
218 lines
5.9 KiB
C
/*
|
|
* The MIT License (MIT)
|
|
*
|
|
* Copyright (c) 2018 Ha Thach for Adafruit Industries
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
* THE SOFTWARE.
|
|
*/
|
|
|
|
#include "boards.h"
|
|
#include "nrf_pwm.h"
|
|
#include "app_scheduler.h"
|
|
#include "app_timer.h"
|
|
|
|
//--------------------------------------------------------------------+
|
|
// MACRO TYPEDEF CONSTANT ENUM DECLARATION
|
|
//--------------------------------------------------------------------+
|
|
#define SCHED_MAX_EVENT_DATA_SIZE sizeof(app_timer_event_t) /**< Maximum size of scheduler events. */
|
|
#define SCHED_QUEUE_SIZE 30 /**< Maximum number of events in the scheduler queue. */
|
|
|
|
//------------- IMPLEMENTATION -------------//
|
|
|
|
void board_init(void)
|
|
{
|
|
// stop LF clock just in case we jump from application without reset
|
|
NRF_CLOCK->TASKS_LFCLKSTOP = 1UL;
|
|
|
|
// Use Internal OSC to compatible with all boards
|
|
NRF_CLOCK->LFCLKSRC = CLOCK_LFCLKSRC_SRC_RC;
|
|
NRF_CLOCK->TASKS_LFCLKSTART = 1UL;
|
|
|
|
// use PMW0 for LED RED
|
|
led_pwm_init(LED_PRIMARY, LED_PRIMARY_PIN);
|
|
#if LEDS_NUMBER > 1
|
|
led_pwm_init(LED_SECONDARY, LED_SECONDARY_PIN);
|
|
#endif
|
|
|
|
// Init scheduler
|
|
APP_SCHED_INIT(SCHED_MAX_EVENT_DATA_SIZE, SCHED_QUEUE_SIZE);
|
|
|
|
// Init app timer (use RTC1)
|
|
app_timer_init();
|
|
|
|
// Configure Systick for led blinky
|
|
NVIC_SetPriority(SysTick_IRQn, 7);
|
|
SysTick_Config(SystemCoreClock/1000);
|
|
}
|
|
|
|
void board_teardown(void)
|
|
{
|
|
// Disable systick, turn off LEDs
|
|
SysTick->CTRL = 0;
|
|
|
|
// Disable and reset PWM for LEDs
|
|
led_pwm_teardown();
|
|
|
|
// Stop RTC1 used by app_timer
|
|
NVIC_DisableIRQ(RTC1_IRQn);
|
|
NRF_RTC1->EVTENCLR = RTC_EVTEN_COMPARE0_Msk;
|
|
NRF_RTC1->INTENCLR = RTC_INTENSET_COMPARE0_Msk;
|
|
NRF_RTC1->TASKS_STOP = 1;
|
|
NRF_RTC1->TASKS_CLEAR = 1;
|
|
|
|
// Stop LF clock
|
|
NRF_CLOCK->TASKS_LFCLKSTOP = 1UL;
|
|
|
|
// make sure all pins are back in reset state
|
|
// NUMBER_OF_PINS is defined in nrf_gpio.h
|
|
for (int i = 0; i < NUMBER_OF_PINS; ++i)
|
|
{
|
|
nrf_gpio_cfg_default(i);
|
|
}
|
|
}
|
|
|
|
static uint32_t _systick_count = 0;
|
|
void SysTick_Handler(void)
|
|
{
|
|
_systick_count++;
|
|
|
|
led_tick();
|
|
}
|
|
|
|
|
|
uint32_t tusb_hal_millis(void)
|
|
{
|
|
return ( ( ((uint64_t)app_timer_cnt_get())*1000*(APP_TIMER_CONFIG_RTC_FREQUENCY+1)) / APP_TIMER_CLOCK_FREQ );
|
|
}
|
|
|
|
void pwm_teardown(NRF_PWM_Type* pwm )
|
|
{
|
|
pwm->TASKS_SEQSTART[0] = 0;
|
|
pwm->ENABLE = 0;
|
|
|
|
pwm->PSEL.OUT[0] = 0xFFFFFFFF;
|
|
pwm->PSEL.OUT[1] = 0xFFFFFFFF;
|
|
pwm->PSEL.OUT[2] = 0xFFFFFFFF;
|
|
pwm->PSEL.OUT[3] = 0xFFFFFFFF;
|
|
|
|
pwm->MODE = 0;
|
|
pwm->COUNTERTOP = 0x3FF;
|
|
pwm->PRESCALER = 0;
|
|
pwm->DECODER = 0;
|
|
pwm->LOOP = 0;
|
|
pwm->SEQ[0].PTR = 0;
|
|
pwm->SEQ[0].CNT = 0;
|
|
}
|
|
|
|
static uint16_t led_duty_cycles[PWM0_CH_NUM] = { 0 };
|
|
|
|
#if LEDS_NUMBER > PWM0_CH_NUM
|
|
#error "Only " PWM0_CH_NUM " concurrent status LEDs are supported."
|
|
#endif
|
|
|
|
void led_pwm_init(uint32_t led_index, uint32_t led_pin)
|
|
{
|
|
NRF_PWM_Type* pwm = NRF_PWM0;
|
|
|
|
pwm->ENABLE = 0;
|
|
|
|
nrf_gpio_cfg_output(led_pin);
|
|
nrf_gpio_pin_write(led_pin, 1 - LED_STATE_ON);
|
|
|
|
pwm->PSEL.OUT[led_index] = led_pin;
|
|
|
|
pwm->MODE = PWM_MODE_UPDOWN_Up;
|
|
pwm->COUNTERTOP = 0xff;
|
|
pwm->PRESCALER = PWM_PRESCALER_PRESCALER_DIV_16;
|
|
pwm->DECODER = PWM_DECODER_LOAD_Individual;
|
|
pwm->LOOP = 0;
|
|
|
|
pwm->SEQ[0].PTR = (uint32_t) (led_duty_cycles);
|
|
pwm->SEQ[0].CNT = 4; // default mode is Individual --> count must be 4
|
|
pwm->SEQ[0].REFRESH = 0;
|
|
pwm->SEQ[0].ENDDELAY = 0;
|
|
|
|
pwm->ENABLE = 1;
|
|
|
|
pwm->EVENTS_SEQEND[0] = 0;
|
|
// pwm->TASKS_SEQSTART[0] = 1;
|
|
}
|
|
|
|
void led_pwm_teardown(void)
|
|
{
|
|
pwm_teardown(NRF_PWM0);
|
|
}
|
|
|
|
void led_pwm_duty_cycle(uint32_t led_index, uint16_t duty_cycle)
|
|
{
|
|
led_duty_cycles[led_index] = duty_cycle;
|
|
nrf_pwm_event_clear(NRF_PWM0, NRF_PWM_EVENT_SEQEND0);
|
|
nrf_pwm_task_trigger(NRF_PWM0, NRF_PWM_TASK_SEQSTART0);
|
|
}
|
|
|
|
static uint32_t primary_cycle_length;
|
|
void led_tick() {
|
|
uint32_t millis = _systick_count;
|
|
|
|
uint32_t cycle = millis % primary_cycle_length;
|
|
uint32_t half_cycle = primary_cycle_length / 2;
|
|
if (cycle > half_cycle) {
|
|
cycle = primary_cycle_length - cycle;
|
|
}
|
|
uint16_t duty_cycle = 0x4f * cycle / half_cycle;
|
|
#if LED_STATE_ON == 1
|
|
duty_cycle = 0xff - duty_cycle;
|
|
#endif
|
|
led_pwm_duty_cycle(LED_PRIMARY, duty_cycle);
|
|
}
|
|
|
|
void led_state(uint32_t state)
|
|
{
|
|
switch (state) {
|
|
case STATE_USB_MOUNTED:
|
|
primary_cycle_length = 3000;
|
|
break;
|
|
|
|
case STATE_BOOTLOADER_STARTED:
|
|
case STATE_USB_UNMOUNTED:
|
|
primary_cycle_length = 300;
|
|
break;
|
|
|
|
case STATE_WRITING_STARTED:
|
|
primary_cycle_length = 100;
|
|
break;
|
|
|
|
case STATE_WRITING_FINISHED:
|
|
// Empty means to unset any temp colors.
|
|
primary_cycle_length = 3000;
|
|
break;
|
|
|
|
case STATE_BLE_CONNECTED:
|
|
primary_cycle_length = 3000;
|
|
break;
|
|
|
|
case STATE_BLE_DISCONNECTED:
|
|
primary_cycle_length = 300;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|