Compare commits

..
7 Commits
Author SHA1 Message Date
Ha Thach 101a54da10 Merge pull request #318 from adafruit/rename-feather-sense-tft
rename to feather sense tft
2024-01-04 18:29:02 +07:00
hathach e81391f395 rename to feather sense tft 2024-01-04 18:23:51 +07:00
Ha Thach eaaf5f8e84 Merge pull request #317 from adafruit/add-feather-tft
Add feather tft
2024-01-03 22:29:26 +07:00
hathach 1c85a7a5be try to install setuptools for linkermap 2024-01-03 22:21:29 +07:00
hathach f5a1947974 add feather tft to ci build 2024-01-03 22:13:28 +07:00
hathach 66db5aeda3 add support for NEOPIXEL_POWER_PIN, also change code style 2024-01-03 22:12:13 +07:00
hathach 36a1f428dd add feather nrf52840 tft 2024-01-03 22:10:22 +07:00
7 changed files with 317 additions and 297 deletions

No files matched your search

+4 -3
View File
@@ -22,6 +22,7 @@ jobs:
- 'feather_nrf52833_express'
- 'feather_nrf52840_express'
- 'feather_nrf52840_sense'
- 'feather_nrf52840_sense_tft'
- 'itsybitsy_nrf52840_express'
- 'metro_nrf52840_express'
- 'ledglasses_nrf52840'
@@ -67,13 +68,13 @@ jobs:
uses: actions/setup-python@v3
- name: Checkout Code
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 0
submodules: true
- name: Checkout linkermap
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
repository: hathach/linkermap
path: linkermap
@@ -85,7 +86,7 @@ jobs:
- name: Install Tools
run: |
pip3 install adafruit-nrfutil uritemplate requests intelhex
pip3 install adafruit-nrfutil uritemplate requests intelhex setuptools
pip3 install linkermap/
- name: Build
+162 -184
View File
@@ -38,35 +38,29 @@
#define SCHED_QUEUE_SIZE 30 /**< Maximum number of events in the scheduler queue. */
#if defined(LED_NEOPIXEL) || defined(LED_RGB_RED_PIN) || defined(LED_APA102)
void neopixel_init(void);
void neopixel_write(uint8_t *pixels);
void neopixel_teardown(void);
void neopixel_init(void);
void neopixel_write(uint8_t* pixels);
void neopixel_teardown(void);
#endif
//------------- IMPLEMENTATION -------------//
void button_init(uint32_t pin)
{
if ( BUTTON_PULL == NRF_GPIO_PIN_PULLDOWN )
{
void button_init(uint32_t pin) {
if (BUTTON_PULL == NRF_GPIO_PIN_PULLDOWN) {
nrf_gpio_cfg_sense_input(pin, BUTTON_PULL, NRF_GPIO_PIN_SENSE_HIGH);
}
else
{
} else {
nrf_gpio_cfg_sense_input(pin, BUTTON_PULL, NRF_GPIO_PIN_SENSE_LOW);
}
}
bool button_pressed(uint32_t pin)
{
bool button_pressed(uint32_t pin) {
uint32_t const active_state = (BUTTON_PULL == NRF_GPIO_PIN_PULLDOWN ? 1 : 0);
return nrf_gpio_pin_read(pin) == active_state;
}
// This is declared so that a board specific init can be called from here.
void __attribute__((weak)) board_init2(void) { }
void __attribute__((weak)) board_init2(void) {}
void board_init(void)
{
void board_init(void) {
// stop LF clock just in case we jump from application without reset
NRF_CLOCK->TASKS_LFCLKSTOP = 1UL;
@@ -85,8 +79,14 @@ void board_init(void)
led_pwm_init(LED_SECONDARY, LED_SECONDARY_PIN);
#endif
#endif
// use neopixel for use enumeration
#if defined(LED_NEOPIXEL) || defined(LED_RGB_RED_PIN) || defined(LED_APA102)
// use neopixel for use enumeration
#ifdef NEOPIXEL_POWER_PIN
nrf_gpio_cfg_output(NEOPIXEL_POWER_PIN);
nrf_gpio_pin_write(NEOPIXEL_POWER_PIN, 1);
#endif
neopixel_init();
#endif
@@ -99,23 +99,21 @@ void board_init(void)
// Make sure any custom inits are performed
board_init2();
// When board is supplied on VDDH (and not VDD), this specifies what voltage the GPIO should run at
// and what voltage is output at VDD. The default (0xffffffff) is 1.8V; typically you'll want
// #define UICR_REGOUT0_VALUE UICR_REGOUT0_VOUT_3V3
// in board.h when using that power configuration.
// When board is supplied on VDDH (and not VDD), this specifies what voltage the GPIO should run at
// and what voltage is output at VDD. The default (0xffffffff) is 1.8V; typically you'll want
// #define UICR_REGOUT0_VALUE UICR_REGOUT0_VOUT_3V3
// in board.h when using that power configuration.
#ifdef UICR_REGOUT0_VALUE
if ((NRF_UICR->REGOUT0 & UICR_REGOUT0_VOUT_Msk) !=
(UICR_REGOUT0_VALUE << UICR_REGOUT0_VOUT_Pos))
{
NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Wen << NVMC_CONFIG_WEN_Pos;
while (NRF_NVMC->READY == NVMC_READY_READY_Busy){}
NRF_UICR->REGOUT0 = (NRF_UICR->REGOUT0 & ~((uint32_t)UICR_REGOUT0_VOUT_Msk)) |
(UICR_REGOUT0_VALUE << UICR_REGOUT0_VOUT_Pos);
if ((NRF_UICR->REGOUT0 & UICR_REGOUT0_VOUT_Msk) != (UICR_REGOUT0_VALUE << UICR_REGOUT0_VOUT_Pos)){
NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Wen << NVMC_CONFIG_WEN_Pos;
while (NRF_NVMC->READY == NVMC_READY_READY_Busy){}
NRF_UICR->REGOUT0 = (NRF_UICR->REGOUT0 & ~((uint32_t)UICR_REGOUT0_VOUT_Msk)) |
(UICR_REGOUT0_VALUE << UICR_REGOUT0_VOUT_Pos);
NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Ren << NVMC_CONFIG_WEN_Pos;
while (NRF_NVMC->READY == NVMC_READY_READY_Busy){}
NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Ren << NVMC_CONFIG_WEN_Pos;
while (NRF_NVMC->READY == NVMC_READY_READY_Busy){}
NVIC_SystemReset();
NVIC_SystemReset();
}
#endif
@@ -127,14 +125,13 @@ void board_init(void)
// Configure Systick for led blinky
NVIC_SetPriority(SysTick_IRQn, 7);
SysTick_Config(SystemCoreClock/1000);
SysTick_Config(SystemCoreClock / 1000);
}
// Actions at the end of board_teardown.
void __attribute__((weak)) board_teardown2(void) { }
void __attribute__((weak)) board_teardown2(void) {}
void board_teardown(void)
{
void board_teardown(void) {
// Disable systick, turn off LEDs
SysTick->CTRL = 0;
@@ -149,9 +146,9 @@ void board_teardown(void)
// 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->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
@@ -159,8 +156,7 @@ void board_teardown(void)
// 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)
{
for (int i = 0; i < NUMBER_OF_PINS; ++i) {
nrf_gpio_cfg_default(i);
}
@@ -169,42 +165,38 @@ void board_teardown(void)
}
static uint32_t _systick_count = 0;
void SysTick_Handler(void)
{
_systick_count++;
void SysTick_Handler(void) {
_systick_count++;
led_tick();
}
void pwm_teardown(NRF_PWM_Type* pwm )
{
void pwm_teardown(NRF_PWM_Type* pwm) {
pwm->TASKS_SEQSTART[0] = 0;
pwm->ENABLE = 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;
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 };
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;
void led_pwm_init(uint32_t led_index, uint32_t led_pin) {
NRF_PWM_Type* pwm = NRF_PWM0;
pwm->ENABLE = 0;
@@ -213,15 +205,15 @@ void led_pwm_init(uint32_t led_index, uint32_t led_pin)
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->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].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;
@@ -230,13 +222,11 @@ void led_pwm_init(uint32_t led_index, uint32_t led_pin)
// pwm->TASKS_SEQSTART[0] = 1;
}
void led_pwm_teardown(void)
{
void led_pwm_teardown(void) {
pwm_teardown(NRF_PWM0);
}
void led_pwm_duty_cycle(uint32_t led_index, uint16_t duty_cycle)
{
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);
@@ -246,102 +236,103 @@ static uint32_t primary_cycle_length;
#ifdef LED_SECONDARY_PIN
static uint32_t secondary_cycle_length;
#endif
void led_tick() {
uint32_t millis = _systick_count;
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);
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);
#ifdef LED_SECONDARY_PIN
cycle = millis % secondary_cycle_length;
half_cycle = secondary_cycle_length / 2;
if (cycle > half_cycle) {
cycle = secondary_cycle_length - cycle;
}
duty_cycle = 0x8f * cycle / half_cycle;
#if LED_STATE_ON == 1
duty_cycle = 0xff - duty_cycle;
#endif
led_pwm_duty_cycle(LED_SECONDARY, duty_cycle);
#endif
#ifdef LED_SECONDARY_PIN
cycle = millis % secondary_cycle_length;
half_cycle = secondary_cycle_length / 2;
if (cycle > half_cycle) {
cycle = secondary_cycle_length - cycle;
}
duty_cycle = 0x8f * cycle / half_cycle;
#if LED_STATE_ON == 1
duty_cycle = 0xff - duty_cycle;
#endif
led_pwm_duty_cycle(LED_SECONDARY, duty_cycle);
#endif
}
static uint32_t rgb_color;
static bool temp_color_active = false;
void led_state(uint32_t state)
{
uint32_t new_rgb_color = rgb_color;
uint32_t temp_color = 0;
switch (state) {
case STATE_USB_MOUNTED:
new_rgb_color = 0x00ff00;
primary_cycle_length = 3000;
break;
case STATE_BOOTLOADER_STARTED:
case STATE_USB_UNMOUNTED:
new_rgb_color = 0xff0000;
primary_cycle_length = 300;
break;
void led_state(uint32_t state) {
uint32_t new_rgb_color = rgb_color;
uint32_t temp_color = 0;
switch (state) {
case STATE_USB_MOUNTED:
new_rgb_color = 0x00ff00;
primary_cycle_length = 3000;
break;
case STATE_WRITING_STARTED:
temp_color = 0xff0000;
primary_cycle_length = 100;
break;
case STATE_BOOTLOADER_STARTED:
case STATE_USB_UNMOUNTED:
new_rgb_color = 0xff0000;
primary_cycle_length = 300;
break;
case STATE_WRITING_FINISHED:
// Empty means to unset any temp colors.
primary_cycle_length = 3000;
break;
case STATE_WRITING_STARTED:
temp_color = 0xff0000;
primary_cycle_length = 100;
break;
case STATE_BLE_CONNECTED:
new_rgb_color = 0x0000ff;
#ifdef LED_SECONDARY_PIN
secondary_cycle_length = 3000;
#else
primary_cycle_length = 3000;
#endif
break;
case STATE_WRITING_FINISHED:
// Empty means to unset any temp colors.
primary_cycle_length = 3000;
break;
case STATE_BLE_DISCONNECTED:
new_rgb_color = 0xff00ff;
#ifdef LED_SECONDARY_PIN
secondary_cycle_length = 300;
#else
primary_cycle_length = 300;
#endif
break;
case STATE_BLE_CONNECTED:
new_rgb_color = 0x0000ff;
#ifdef LED_SECONDARY_PIN
secondary_cycle_length = 3000;
#else
primary_cycle_length = 3000;
#endif
break;
default:
break;
}
uint8_t* final_color = NULL;
new_rgb_color &= BOARD_RGB_BRIGHTNESS;
if (temp_color != 0){
temp_color &= BOARD_RGB_BRIGHTNESS;
final_color = (uint8_t*)&temp_color;
temp_color_active = true;
} else if (new_rgb_color != rgb_color) {
final_color = (uint8_t*)&new_rgb_color;
rgb_color = new_rgb_color;
} else if (temp_color_active) {
final_color = (uint8_t*)&rgb_color;
}
case STATE_BLE_DISCONNECTED:
new_rgb_color = 0xff00ff;
#ifdef LED_SECONDARY_PIN
secondary_cycle_length = 300;
#else
primary_cycle_length = 300;
#endif
break;
default:
break;
}
uint8_t* final_color = NULL;
new_rgb_color &= BOARD_RGB_BRIGHTNESS;
if (temp_color != 0) {
temp_color &= BOARD_RGB_BRIGHTNESS;
final_color = (uint8_t*) &temp_color;
temp_color_active = true;
} else if (new_rgb_color != rgb_color) {
final_color = (uint8_t*) &new_rgb_color;
rgb_color = new_rgb_color;
} else if (temp_color_active) {
final_color = (uint8_t*) &rgb_color;
}
#if defined(LED_NEOPIXEL) || defined(LED_RGB_RED_PIN) || defined(LED_APA102)
if (final_color != NULL) {
neopixel_write(final_color);
}
if (final_color != NULL) {
neopixel_write(final_color);
}
#else
(void) final_color;
(void) final_color;
#endif
}
@@ -354,11 +345,10 @@ void led_state(uint32_t state)
#define BYTE_PER_PIXEL 3
static uint16_t pixels_pattern[NEOPIXELS_NUMBER*BYTE_PER_PIXEL * 8 + 2];
static uint16_t pixels_pattern[NEOPIXELS_NUMBER * BYTE_PER_PIXEL * 8 + 2];
// use PWM1 for neopixel
void neopixel_init(void)
{
void neopixel_init(void) {
// To support both the SoftDevice + Neopixels we use the EasyDMA
// feature from the NRF25. However this technique implies to
// generate a pattern and store it on the memory. The actual
@@ -394,40 +384,33 @@ void neopixel_init(void)
// pwm->INTEN |= (PWM_INTEN_SEQEND0_Enabled<<PWM_INTEN_SEQEND0_Pos);
// PSEL must be configured before enabling PWM
nrf_pwm_pins_set(pwm, (uint32_t[] ) { LED_NEOPIXEL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL });
nrf_pwm_pins_set(pwm, (uint32_t[]) {LED_NEOPIXEL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL});
// Enable the PWM
nrf_pwm_enable(pwm);
}
void neopixel_teardown(void)
{
uint8_t rgb[3] = { 0, 0, 0 };
void neopixel_teardown(void) {
uint8_t rgb[3] = {0, 0, 0};
NRFX_DELAY_US(50); // wait for previous write is complete
neopixel_write(rgb);
NRFX_DELAY_US(50); // wait for this write
pwm_teardown(NRF_PWM1);
}
// write 3 bytes color RGB to built-in neopixel
void neopixel_write (uint8_t *pixels)
{
void neopixel_write(uint8_t* pixels) {
// convert RGB to GRB
uint8_t grb[BYTE_PER_PIXEL] = {pixels[1], pixels[2], pixels[0]};
uint16_t pos = 0; // bit position
// Set all neopixel to same value
for (uint16_t n = 0; n < NEOPIXELS_NUMBER; n++ )
{
for(uint8_t c = 0; c < BYTE_PER_PIXEL; c++)
{
for (uint16_t n = 0; n < NEOPIXELS_NUMBER; n++) {
for (uint8_t c = 0; c < BYTE_PER_PIXEL; c++) {
uint8_t const pix = grb[c];
for ( uint8_t mask = 0x80; mask > 0; mask >>= 1 )
{
for (uint8_t mask = 0x80; mask > 0; mask >>= 1) {
pixels_pattern[pos] = (pix & mask) ? MAGIC_T1H : MAGIC_T0H;
pos++;
}
@@ -441,14 +424,15 @@ void neopixel_write (uint8_t *pixels)
NRF_PWM_Type* pwm = NRF_PWM1;
nrf_pwm_seq_ptr_set(pwm, 0, pixels_pattern);
nrf_pwm_seq_cnt_set(pwm, 0, sizeof(pixels_pattern)/2);
nrf_pwm_seq_cnt_set(pwm, 0, sizeof(pixels_pattern) / 2);
nrf_pwm_event_clear(pwm, NRF_PWM_EVENT_SEQEND0);
nrf_pwm_task_trigger(pwm, NRF_PWM_TASK_SEQSTART0);
// blocking wait for sequence complete
while( !nrf_pwm_event_check(pwm, NRF_PWM_EVENT_SEQEND0) ) {}
while (!nrf_pwm_event_check(pwm, NRF_PWM_EVENT_SEQEND0)) {}
nrf_pwm_event_clear(pwm, NRF_PWM_EVENT_SEQEND0);
}
#endif
#ifdef LED_APA102
@@ -460,8 +444,7 @@ void neopixel_write (uint8_t *pixels)
static uint8_t pixels_pattern[PATTERN_SIZE() + 4];
// use SPIM1 for dotstar
void neopixel_init(void)
{
void neopixel_init(void) {
NRF_SPIM_Type* spi = NRF_SPIM1;
nrf_spim_disable(spi);
@@ -492,8 +475,7 @@ void neopixel_init(void)
neopixel_write(rgb);
}
void neopixel_teardown(void)
{
void neopixel_teardown(void) {
uint8_t rgb[3] = {0, 0, 0 };
neopixel_write(rgb);
@@ -502,8 +484,7 @@ void neopixel_teardown(void)
}
// write 3 bytes color RGB to built-in neopixel
void neopixel_write (uint8_t *pixels)
{
void neopixel_write (uint8_t *pixels) {
NRF_SPIM_Type* spi = NRF_SPIM1;
//brightness, blue, green, red
@@ -514,10 +495,10 @@ void neopixel_write (uint8_t *pixels)
pixels_pattern[3] = 0;
for (uint8_t i = 4; i < PATTERN_SIZE(); i+=4) {
pixels_pattern[i] = bbgr[0];
pixels_pattern[i+1] = bbgr[1];
pixels_pattern[i+2] = bbgr[2];
pixels_pattern[i+3] = bbgr[3];
pixels_pattern[i] = bbgr[0];
pixels_pattern[i+1] = bbgr[1];
pixels_pattern[i+2] = bbgr[2];
pixels_pattern[i+3] = bbgr[3];
}
pixels_pattern[PATTERN_SIZE()] = 0xff;
@@ -545,15 +526,13 @@ void neopixel_write (uint8_t *pixels)
#define LED_RGB_BLUE 2
#define LED_RGB_GREEN 3
void neopixel_init(void)
{
void neopixel_init(void) {
led_pwm_init(LED_RGB_RED, LED_RGB_RED_PIN);
led_pwm_init(LED_RGB_GREEN, LED_RGB_GREEN_PIN);
led_pwm_init(LED_RGB_BLUE, LED_RGB_BLUE_PIN);
}
void neopixel_teardown(void)
{
void neopixel_teardown(void) {
uint8_t rgb[3] = { 0, 0, 0 };
neopixel_write(rgb);
nrf_gpio_cfg_default(LED_RGB_RED_PIN);
@@ -562,8 +541,7 @@ void neopixel_teardown(void)
}
// write 3 bytes color to a built-in neopixel
void neopixel_write (uint8_t *pixels)
{
void neopixel_write (uint8_t *pixels) {
led_pwm_duty_cycle(LED_RGB_RED, pixels[2]);
led_pwm_duty_cycle(LED_RGB_GREEN, pixels[1]);
led_pwm_duty_cycle(LED_RGB_BLUE, pixels[0]);
@@ -0,0 +1 @@
set(MCU_VARIANT nrf52840)
@@ -0,0 +1,69 @@
/*
* 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.
*/
#ifndef _FEATHER_NRF52840_SENSE_TFT_H
#define _FEATHER_NRF52840_SENSE_TFT_H
#define _PINNUM(port, pin) ((port)*32 + (pin))
/*------------------------------------------------------------------*/
/* LED
*------------------------------------------------------------------*/
#define LEDS_NUMBER 1
#define LED_PRIMARY_PIN _PINNUM(0, 11)
#define LED_STATE_ON 1
#define LED_NEOPIXEL _PINNUM(1, 8)
#define NEOPIXEL_POWER_PIN _PINNUM(1, 2)
#define NEOPIXELS_NUMBER 1
#define BOARD_RGB_BRIGHTNESS 0x040404
/*------------------------------------------------------------------*/
/* BUTTON
*------------------------------------------------------------------*/
#define BUTTONS_NUMBER 2
#define BUTTON_1 _PINNUM(1, 6)
#define BUTTON_2 _PINNUM(1, 10) // DFU pin
#define BUTTON_PULL NRF_GPIO_PIN_PULLUP
//--------------------------------------------------------------------+
// BLE OTA
//--------------------------------------------------------------------+
#define BLEDIS_MANUFACTURER "Adafruit Industries"
#define BLEDIS_MODEL "Feather nRF52840 Sense TFT"
//--------------------------------------------------------------------+
// USB
//--------------------------------------------------------------------+
#define USB_DESC_VID 0x239A
#define USB_DESC_UF2_PID 0x0087
#define USB_DESC_CDC_ONLY_PID 0x0088
//------------- UF2 -------------//
#define UF2_PRODUCT_NAME "Adafruit Feather nRF52840 Sense TFT"
#define UF2_VOLUME_LABEL "FTHRSNSBOOT"
#define UF2_BOARD_ID "nRF52840-FeatherSenseTFT-revA"
#define UF2_INDEX_URL "https://www.adafruit.com/product/"
#endif
@@ -0,0 +1 @@
MCU_SUB_VARIANT = nrf52840
@@ -0,0 +1,19 @@
#include "boards.h"
#include "uf2/configkeys.h"
__attribute__((used, section(".bootloaderConfig")))
const uint32_t bootloaderConfig[] =
{
/* CF2 START */
CFG_MAGIC0, CFG_MAGIC1, // magic
5, 100, // used entries, total entries
204, 0x100000, // FLASH_BYTES = 0x100000
205, 0x40000, // RAM_BYTES = 0x40000
208, (USB_DESC_VID << 16) | USB_DESC_UF2_PID, // BOOTLOADER_BOARD_ID = USB VID+PID, used for verification when updating bootloader via uf2
209, 0xada52840, // UF2_FAMILY = 0xada52840
210, 0x20, // PINS_PORT_SIZE = PA_32
0, 0, 0, 0, 0, 0, 0, 0
/* CF2 END */
};
+61 -110
View File
@@ -68,6 +68,7 @@
#include "nrfx_nvmc.h"
#ifdef NRF_USBD
#include "uf2/uf2.h"
#include "nrf_usbd.h"
#include "tusb.h"
@@ -80,16 +81,11 @@ void usb_teardown(void);
extern void tusb_hal_nrf_power_event(uint32_t event);
#else
#define usb_init(x) led_state(STATE_USB_MOUNTED) // mark nrf52832 as mounted
#define usb_teardown()
#endif
//--------------------------------------------------------------------+
//
//--------------------------------------------------------------------+
/*
* Blinking patterns:
* - DFU Serial : LED Status blink
@@ -132,20 +128,21 @@ extern void tusb_hal_nrf_power_event(uint32_t event);
// These value must be the same with one in dfu_transport_ble.c
#define BLEGAP_EVENT_LENGTH 6
#define BLEGATT_ATT_MTU_MAX 23
enum { BLE_CONN_CFG_HIGH_BANDWIDTH = 1 };
enum {
BLE_CONN_CFG_HIGH_BANDWIDTH = 1
};
//--------------------------------------------------------------------+
//
//--------------------------------------------------------------------+
uint32_t* dbl_reset_mem = ((uint32_t*) DFU_DBL_RESET_MEM );
uint32_t* dbl_reset_mem = ((uint32_t*) DFU_DBL_RESET_MEM);
// true if ble, false if serial
bool _ota_dfu = false;
bool _ota_connected = false;
bool _sd_inited = false;
bool is_ota(void)
{
bool is_ota(void) {
return _ota_dfu;
}
@@ -154,18 +151,16 @@ static uint32_t ble_stack_init(void);
// The SoftDevice must only be initialized if a chip reset has occurred.
// Soft reset (jump ) from application must not reinitialize the SoftDevice.
static void mbr_init_sd(void)
{
static void mbr_init_sd(void) {
PRINTF("SD_MBR_COMMAND_INIT_SD\r\n");
sd_mbr_command_t com = { .command = SD_MBR_COMMAND_INIT_SD };
sd_mbr_command_t com = {.command = SD_MBR_COMMAND_INIT_SD};
sd_mbr_command(&com);
}
//--------------------------------------------------------------------+
//
//--------------------------------------------------------------------+
int main(void)
{
int main(void) {
// Populate Boot Address and MBR Param into MBR if not already
// MBR_BOOTLOADER_ADDR/MBR_PARAM_PAGE_ADDR are used if available, else UICR registers are used
// Note: skip it for now since this will prevent us to change the size of bootloader in the future
@@ -177,14 +172,11 @@ int main(void)
board_init();
bootloader_init();
PRINTF("Bootloader Start\r\n");
led_state(STATE_BOOTLOADER_STARTED);
// When updating SoftDevice, bootloader will reset before swapping SD
if (bootloader_dfu_sd_in_progress())
{
if (bootloader_dfu_sd_in_progress()) {
led_state(STATE_WRITING_STARTED);
bootloader_dfu_sd_update_continue();
@@ -207,14 +199,11 @@ int main(void)
* - sd_softdevice_vector_table_base_set(APP_ADDR)
* - jump to App reset
*/
if (bootloader_app_is_valid() && !bootloader_dfu_sd_in_progress())
{
if (bootloader_app_is_valid() && !bootloader_dfu_sd_in_progress()) {
PRINTF("App is valid\r\n");
if ( is_sd_existed() )
{
if (is_sd_existed()) {
// MBR forward IRQ to SD (if not already)
if ( !_sd_inited ) mbr_init_sd();
if (!_sd_inited) mbr_init_sd();
// Make sure SD is disabled
sd_softdevice_disable();
@@ -230,8 +219,7 @@ int main(void)
NVIC_SystemReset();
}
static void check_dfu_mode(void)
{
static void check_dfu_mode(void) {
uint32_t const gpregret = NRF_POWER->GPREGRET;
// SD is already Initialized in case of BOOTLOADER_DFU_OTA_MAGIC
@@ -249,7 +237,7 @@ static void check_dfu_mode(void)
// start either serial, uf2 or ble
bool dfu_start = _ota_dfu || serial_only_dfu || uf2_dfu ||
(((*dbl_reset_mem) == DFU_DBL_RESET_MAGIC) && reason_reset_pin);
(((*dbl_reset_mem) == DFU_DBL_RESET_MAGIC) && reason_reset_pin);
// Clear GPREGRET if it is our values
if (dfu_start || dfu_skip) NRF_POWER->GPREGRET = 0;
@@ -262,7 +250,7 @@ static void check_dfu_mode(void)
dfu_start = dfu_start || button_pressed(BUTTON_DFU);
// DFU + FRESET are pressed --> OTA
_ota_dfu = _ota_dfu || ( button_pressed(BUTTON_DFU) && button_pressed(BUTTON_FRESET) ) ;
_ota_dfu = _ota_dfu || (button_pressed(BUTTON_DFU) && button_pressed(BUTTON_FRESET));
bool const valid_app = bootloader_app_is_valid();
bool const just_start_app = valid_app && !dfu_start && (*dbl_reset_mem) == DFU_DBL_RESET_APP;
@@ -270,8 +258,7 @@ static void check_dfu_mode(void)
if (!just_start_app && APP_ASKS_FOR_SINGLE_TAP_RESET()) dfu_start = 1;
// App mode: Double Reset detection or DFU startup for nrf52832
if ( ! (just_start_app || dfu_start || !valid_app) )
{
if (!(just_start_app || dfu_start || !valid_app)) {
#ifdef NRF52832_XXAA
/* Even DFU is not active, we still force an 1000 ms dfu serial mode when startup
* to support auto programming from Arduino IDE
@@ -281,8 +268,7 @@ static void check_dfu_mode(void)
bootloader_dfu_start(false, DFU_SERIAL_STARTUP_INTERVAL, false);
#else
// Note: RESETREAS is not clear by bootloader, it should be cleared by application upon init()
if (reason_reset_pin)
{
if (reason_reset_pin) {
// Register our first reset for double reset detection
(*dbl_reset_mem) = DFU_DBL_RESET_MAGIC;
@@ -292,77 +278,59 @@ static void check_dfu_mode(void)
#endif
}
if (APP_ASKS_FOR_SINGLE_TAP_RESET())
{
if (APP_ASKS_FOR_SINGLE_TAP_RESET()) {
(*dbl_reset_mem) = DFU_DBL_RESET_APP;
}
else
{
} else {
(*dbl_reset_mem) = 0;
}
// Enter DFU mode accordingly to input
if ( dfu_start || !valid_app )
{
if ( _ota_dfu )
{
if (dfu_start || !valid_app) {
if (_ota_dfu) {
led_state(STATE_BLE_DISCONNECTED);
if (!_sd_inited ) mbr_init_sd();
if (!_sd_inited) mbr_init_sd();
_sd_inited = true;
ble_stack_init();
}
else
{
} else {
led_state(STATE_USB_UNMOUNTED);
usb_init(serial_only_dfu);
}
// Initiate an update of the firmware.
if (APP_ASKS_FOR_SINGLE_TAP_RESET() || uf2_dfu || serial_only_dfu)
{
if (APP_ASKS_FOR_SINGLE_TAP_RESET() || uf2_dfu || serial_only_dfu) {
// If USB is not enumerated in 3s (eg. because we're running on battery), we restart into app.
bootloader_dfu_start(_ota_dfu, 3000, true);
}
else
{
bootloader_dfu_start(_ota_dfu, 3000, true);
} else {
// No timeout if bootloader requires user action (double-reset).
bootloader_dfu_start(_ota_dfu, 0, false);
bootloader_dfu_start(_ota_dfu, 0, false);
}
if ( _ota_dfu )
{
if (_ota_dfu) {
sd_softdevice_disable();
}else
{
} else {
usb_teardown();
}
}
}
// Initializes the SotdDevice by following SD specs section
// "Master Boot Record and SoftDevice initializaton procedure"
static uint32_t ble_stack_init(void)
{
static uint32_t ble_stack_init(void) {
// Forward vector table to bootloader address so that we can handle BLE events
sd_softdevice_vector_table_base_set(BOOTLOADER_REGION_START);
// Enable Softdevice, Use Internal OSC to compatible with all boards
nrf_clock_lf_cfg_t clock_cfg =
{
nrf_clock_lf_cfg_t clock_cfg = {
.source = NRF_CLOCK_LF_SRC_RC,
.rc_ctiv = 16,
.rc_temp_ctiv = 2,
.accuracy = NRF_CLOCK_LF_ACCURACY_250_PPM
};
sd_softdevice_enable(&clock_cfg, app_error_fault_handler);
sd_nvic_EnableIRQ(SD_EVT_IRQn);
/*------------- Configure BLE params -------------*/
extern uint32_t __data_start__[]; // defined in linker
extern uint32_t __data_start__[]; // defined in linker
uint32_t ram_start = (uint32_t) __data_start__;
ble_cfg_t blecfg;
@@ -370,9 +338,9 @@ static uint32_t ble_stack_init(void)
// Configure the maximum number of connections.
varclr(&blecfg);
blecfg.gap_cfg.role_count_cfg.adv_set_count = 1;
blecfg.gap_cfg.role_count_cfg.periph_role_count = 1;
blecfg.gap_cfg.role_count_cfg.periph_role_count = 1;
blecfg.gap_cfg.role_count_cfg.central_role_count = 0;
blecfg.gap_cfg.role_count_cfg.central_sec_count = 0;
blecfg.gap_cfg.role_count_cfg.central_sec_count = 0;
sd_ble_cfg_set(BLE_GAP_CFG_ROLE_COUNT, &blecfg, ram_start);
// NRF_DFU_BLE_REQUIRES_BONDS
@@ -389,7 +357,7 @@ static uint32_t ble_stack_init(void)
// Event Length + HVN queue + WRITE CMD queue setting affecting bandwidth
varclr(&blecfg);
blecfg.conn_cfg.conn_cfg_tag = BLE_CONN_CFG_HIGH_BANDWIDTH;
blecfg.conn_cfg.params.gap_conn_cfg.conn_count = 1;
blecfg.conn_cfg.params.gap_conn_cfg.conn_count = 1;
blecfg.conn_cfg.params.gap_conn_cfg.event_length = BLEGAP_EVENT_LENGTH;
sd_ble_cfg_set(BLE_CONN_CFG_GAP, &blecfg, ram_start);
@@ -407,19 +375,16 @@ static uint32_t ble_stack_init(void)
return NRF_SUCCESS;
}
//--------------------------------------------------------------------+
// Error Handler
//--------------------------------------------------------------------+
void app_error_fault_handler(uint32_t id, uint32_t pc, uint32_t info)
{
volatile uint32_t* ARM_CM_DHCSR = ((volatile uint32_t*) 0xE000EDF0UL); /* Cortex M CoreDebug->DHCSR */
if ( (*ARM_CM_DHCSR) & 1UL ) __asm("BKPT #0\n"); /* Only halt mcu if debugger is attached */
void app_error_fault_handler(uint32_t id, uint32_t pc, uint32_t info) {
volatile uint32_t* ARM_CM_DHCSR = ((volatile uint32_t*) 0xE000EDF0UL); /* Cortex M CoreDebug->DHCSR */
if ((*ARM_CM_DHCSR) & 1UL) __asm("BKPT #0\n"); /* Only halt mcu if debugger is attached */
NVIC_SystemReset();
}
void assert_nrf_callback (uint16_t line_num, uint8_t const * p_file_name)
{
void assert_nrf_callback(uint16_t line_num, uint8_t const* p_file_name) {
app_error_fault_handler(0xDEADBEEF, 0, 0);
}
@@ -428,9 +393,8 @@ void assert_nrf_callback (uint16_t line_num, uint8_t const * p_file_name)
*------------------------------------------------------------------*/
// Process BLE event from SD
uint32_t proc_ble(void)
{
__ALIGN(4) uint8_t ev_buf[ BLE_EVT_LEN_MAX(BLEGATT_ATT_MTU_MAX) ];
uint32_t proc_ble(void) {
__ALIGN(4) uint8_t ev_buf[BLE_EVT_LEN_MAX(BLEGATT_ATT_MTU_MAX)];
uint16_t ev_len = BLE_EVT_LEN_MAX(BLEGATT_ATT_MTU_MAX);
// Init header
@@ -441,25 +405,24 @@ uint32_t proc_ble(void)
uint32_t err = sd_ble_evt_get(ev_buf, &ev_len);
// Handle valid event, ignore error
if( NRF_SUCCESS == err)
{
switch (evt->header.evt_id)
{
if (NRF_SUCCESS == err) {
switch (evt->header.evt_id) {
case BLE_GAP_EVT_CONNECTED:
_ota_connected = true;
led_state(STATE_BLE_CONNECTED);
break;
break;
case BLE_GAP_EVT_DISCONNECTED:
_ota_connected = false;
led_state(STATE_BLE_DISCONNECTED);
break;
break;
default: break;
default:
break;
}
// from dfu_transport_ble
extern void ble_evt_dispatch(ble_evt_t * p_ble_evt);
extern void ble_evt_dispatch(ble_evt_t* p_ble_evt);
ble_evt_dispatch(evt);
}
@@ -467,68 +430,56 @@ uint32_t proc_ble(void)
}
// process SOC event from SD
uint32_t proc_soc(void)
{
uint32_t proc_soc(void) {
uint32_t soc_evt = 0;
uint32_t err = sd_evt_get(&soc_evt);
if (NRF_SUCCESS == err)
{
if (NRF_SUCCESS == err) {
pstorage_sys_event_handler(soc_evt);
#ifdef NRF_USBD
/*------------- usb power event handler -------------*/
int32_t usbevt = (soc_evt == NRF_EVT_POWER_USB_DETECTED ) ? NRFX_POWER_USB_EVT_DETECTED:
(soc_evt == NRF_EVT_POWER_USB_POWER_READY) ? NRFX_POWER_USB_EVT_READY :
(soc_evt == NRF_EVT_POWER_USB_REMOVED ) ? NRFX_POWER_USB_EVT_REMOVED : -1;
int32_t usbevt = (soc_evt == NRF_EVT_POWER_USB_DETECTED) ? NRFX_POWER_USB_EVT_DETECTED :
(soc_evt == NRF_EVT_POWER_USB_POWER_READY) ? NRFX_POWER_USB_EVT_READY :
(soc_evt == NRF_EVT_POWER_USB_REMOVED) ? NRFX_POWER_USB_EVT_REMOVED : -1;
if ( usbevt >= 0) tusb_hal_nrf_power_event((uint32_t) usbevt);
if (usbevt >= 0) tusb_hal_nrf_power_event((uint32_t) usbevt);
#endif
}
return err;
}
void proc_sd_task(void* evt_data, uint16_t evt_size)
{
void proc_sd_task(void* evt_data, uint16_t evt_size) {
(void) evt_data;
(void) evt_size;
// process BLE and SOC until there is no more events
while( (NRF_ERROR_NOT_FOUND != proc_ble()) || (NRF_ERROR_NOT_FOUND != proc_soc()) )
{
while ((NRF_ERROR_NOT_FOUND != proc_ble()) || (NRF_ERROR_NOT_FOUND != proc_soc())) {
// nothing
}
}
void SD_EVT_IRQHandler(void)
{
void SD_EVT_IRQHandler(void) {
// Use App Scheduler to defer handling code in non-isr context
app_sched_event_put(NULL, 0, proc_sd_task);
}
//--------------------------------------------------------------------+
// RTT printf retarget for Debug
//--------------------------------------------------------------------+
#ifdef CFG_DEBUG
#include "SEGGER_RTT.h"
__attribute__ ((used))
int _write (int fhdl, const void *buf, size_t count)
{
__attribute__ ((used)) int _write (int fhdl, const void *buf, size_t count) {
(void) fhdl;
SEGGER_RTT_Write(0, (char*) buf, (int) count);
return count;
}
__attribute__ ((used))
int _read (int fhdl, char *buf, size_t count)
{
__attribute__ ((used)) int _read (int fhdl, char *buf, size_t count) {
(void) fhdl;
return SEGGER_RTT_Read(0, buf, count);
}
#endif