diff --git a/.github/workflows/githubci.yml b/.github/workflows/githubci.yml index a6bb95ea..8ecc30d4 100644 --- a/.github/workflows/githubci.yml +++ b/.github/workflows/githubci.yml @@ -21,6 +21,7 @@ jobs: - 'feather_nrf52832' - 'feather_nrf52833_express' - 'feather_nrf52840_express' + - 'feather_nrf52840_tft' - 'feather_nrf52840_sense' - 'itsybitsy_nrf52840_express' - 'metro_nrf52840_express' @@ -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 diff --git a/src/boards/boards.c b/src/boards/boards.c index de95950c..8b4583fb 100644 --- a/src/boards/boards.c +++ b/src/boards/boards.c @@ -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); - - NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Ren << NVMC_CONFIG_WEN_Pos; - while (NRF_NVMC->READY == NVMC_READY_READY_Busy){} - - NVIC_SystemReset(); + 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){} + + 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); - - #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 + 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 } 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; - - case STATE_WRITING_STARTED: - temp_color = 0xff0000; - 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: - new_rgb_color = 0x0000ff; - #ifdef LED_SECONDARY_PIN - secondary_cycle_length = 3000; - #else - primary_cycle_length = 3000; - #endif - break; - - 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; - } + +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; + + case STATE_WRITING_STARTED: + temp_color = 0xff0000; + 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: + new_rgb_color = 0x0000ff; + #ifdef LED_SECONDARY_PIN + secondary_cycle_length = 3000; + #else + primary_cycle_length = 3000; + #endif + break; + + 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< 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]); diff --git a/src/boards/feather_nrf52840_tft/board.cmake b/src/boards/feather_nrf52840_tft/board.cmake new file mode 100644 index 00000000..25daf71d --- /dev/null +++ b/src/boards/feather_nrf52840_tft/board.cmake @@ -0,0 +1 @@ +set(MCU_VARIANT nrf52840) diff --git a/src/boards/feather_nrf52840_tft/board.h b/src/boards/feather_nrf52840_tft/board.h new file mode 100644 index 00000000..8e3ad8d4 --- /dev/null +++ b/src/boards/feather_nrf52840_tft/board.h @@ -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_TFT_H +#define _FEATHER_NRF52840_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, 4) // not connected +#define BUTTON_PULL NRF_GPIO_PIN_PULLUP + +//--------------------------------------------------------------------+ +// BLE OTA +//--------------------------------------------------------------------+ +#define BLEDIS_MANUFACTURER "Adafruit Industries" +#define BLEDIS_MODEL "Feather nRF52840 TFT" + +//--------------------------------------------------------------------+ +// USB +//--------------------------------------------------------------------+ +#define USB_DESC_VID 0x239A +#define USB_DESC_UF2_PID 0x0029 +#define USB_DESC_CDC_ONLY_PID 0x002A + +//------------- UF2 -------------// +#define UF2_PRODUCT_NAME "Adafruit Feather nRF52840 TFT" +#define UF2_VOLUME_LABEL "FTHR840BOOT" +#define UF2_BOARD_ID "nRF52840-FeatherTFT-revA" +#define UF2_INDEX_URL "https://www.adafruit.com/product/" + +#endif diff --git a/src/boards/feather_nrf52840_tft/board.mk b/src/boards/feather_nrf52840_tft/board.mk new file mode 100644 index 00000000..9d29ac69 --- /dev/null +++ b/src/boards/feather_nrf52840_tft/board.mk @@ -0,0 +1 @@ +MCU_SUB_VARIANT = nrf52840 diff --git a/src/boards/feather_nrf52840_tft/pinconfig.c b/src/boards/feather_nrf52840_tft/pinconfig.c new file mode 100644 index 00000000..a983e4ab --- /dev/null +++ b/src/boards/feather_nrf52840_tft/pinconfig.c @@ -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 */ +}; diff --git a/src/main.c b/src/main.c index 960daa4f..cf005419 100644 --- a/src/main.c +++ b/src/main.c @@ -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