add neopixel support
This commit is contained in:
		
							
								
								
									
										134
									
								
								src/boards.c
									
									
									
									
									
								
							
							
						
						
									
										134
									
								
								src/boards.c
									
									
									
									
									
								
							| @@ -35,6 +35,7 @@ | |||||||
| /**************************************************************************/ | /**************************************************************************/ | ||||||
|  |  | ||||||
| #include "boards.h" | #include "boards.h" | ||||||
|  | #include "nrf_pwm.h" | ||||||
| #include "app_scheduler.h" | #include "app_scheduler.h" | ||||||
| #include "app_timer.h" | #include "app_timer.h" | ||||||
|  |  | ||||||
| @@ -83,7 +84,11 @@ void board_init(void) | |||||||
|  |  | ||||||
| // use neopixel for use enumeration | // use neopixel for use enumeration | ||||||
| #ifdef LED_NEOPIXEL | #ifdef LED_NEOPIXEL | ||||||
|  |   extern void neopixel_init(void); | ||||||
|  |   neopixel_init(); | ||||||
|  |  | ||||||
|  |   uint8_t grb[] = { 0, 255, 0 }; | ||||||
|  |   neopixel_write(grb); | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|   // Init scheduler |   // Init scheduler | ||||||
| @@ -98,6 +103,11 @@ void board_teardown(void) | |||||||
|   // Disable and reset PWM for LED |   // Disable and reset PWM for LED | ||||||
|   led_pwm_teardown(LED_RED); |   led_pwm_teardown(LED_RED); | ||||||
|  |  | ||||||
|  | #ifdef LED_NEOPIXEL | ||||||
|  |   extern void neopixel_teardown(void); | ||||||
|  |   neopixel_teardown(); | ||||||
|  | #endif | ||||||
|  |  | ||||||
|   led_off(LED_BLUE); |   led_off(LED_BLUE); | ||||||
|   led_off(LED_RED); |   led_off(LED_RED); | ||||||
|  |  | ||||||
| @@ -119,25 +129,26 @@ uint32_t tusb_hal_millis(void) | |||||||
|   return ( ( ((uint64_t)app_timer_cnt_get())*1000*(APP_TIMER_CONFIG_RTC_FREQUENCY+1)) / APP_TIMER_CLOCK_FREQ ); |   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->MODE        = 0; | ||||||
|  |   pwm->COUNTERTOP  = 0x3FF; | ||||||
|  |   pwm->PRESCALER   = 0; | ||||||
|  |   pwm->DECODER     = 0; | ||||||
|  |   pwm->LOOP        = 0; | ||||||
|  |   pwm->SEQ[0].PTR  = 0; | ||||||
|  |   pwm->SEQ[0].CNT  = 0; | ||||||
|  | } | ||||||
|  |  | ||||||
| void led_pwm_init(uint32_t led_pin) | void led_pwm_init(uint32_t led_pin) | ||||||
| { | { | ||||||
|   NRF_PWM_Type* pwm    = (led_pin == LED_RED) ? NRF_PWM0 : NRF_PWM1; |   pwm_teardown ((led_pin == LED_RED) ? NRF_PWM0 : NRF_PWM1); | ||||||
|  |  | ||||||
|   pwm->MODE            = PWM_MODE_UPDOWN_UpAndDown; |  | ||||||
|   pwm->COUNTERTOP      = PWM_MAXCOUNT; |  | ||||||
|   pwm->PRESCALER       = PWM_PRESCALER_PRESCALER_DIV_128; |  | ||||||
|   pwm->DECODER         = PWM_DECODER_LOAD_Individual; |  | ||||||
|   pwm->LOOP            = 0; |  | ||||||
|  |  | ||||||
|   pwm->SEQ[0].PTR      = (uint32_t) (led_pin == LED_RED ? _pwm_red_seq : _pwm_blue_seq); |  | ||||||
|   pwm->SEQ[0].CNT      = PWM_CHANNEL_NUM; // default mode is Individual --> count must be 4 |  | ||||||
|   pwm->SEQ[0].REFRESH  = 0; |  | ||||||
|   pwm->SEQ[0].ENDDELAY = 0; |  | ||||||
|  |  | ||||||
|   pwm->PSEL.OUT[0] = led_pin; |  | ||||||
|  |  | ||||||
|   pwm->ENABLE = 1; |  | ||||||
|   pwm->TASKS_SEQSTART[0] = 1; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| void led_pwm_teardown(uint32_t led_pin) | void led_pwm_teardown(uint32_t led_pin) | ||||||
| @@ -186,3 +197,92 @@ void led_red_blink_fast(bool enable) | |||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #if LED_NEOPIXEL | ||||||
|  |  | ||||||
|  | // WS2812B (rev B) timing is 0.4 and 0.8 us | ||||||
|  | #define MAGIC_T0H               6UL | (0x8000) // 0.375us | ||||||
|  | #define MAGIC_T1H              13UL | (0x8000) // 0.8125us | ||||||
|  | #define CTOPVAL                20UL            // 1.25us | ||||||
|  |  | ||||||
|  | #define NEO_NUMBYTE  3 | ||||||
|  |  | ||||||
|  | static uint16_t pixels_pattern[NEO_NUMBYTE * 8 + 2]; | ||||||
|  |  | ||||||
|  | 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 | ||||||
|  |   // memory used in bytes corresponds to the following formula: | ||||||
|  |   //              totalMem = numBytes*8*2+(2*2) | ||||||
|  |   // The two additional bytes at the end are needed to reset the | ||||||
|  |   // sequence. | ||||||
|  |   NRF_PWM_Type* pwm = NRF_PWM2; | ||||||
|  |  | ||||||
|  |   // Set the wave mode to count UP | ||||||
|  |   // Set the PWM to use the 16MHz clock | ||||||
|  |   // Setting of the maximum count | ||||||
|  |   // but keeping it on 16Mhz allows for more granularity just | ||||||
|  |   // in case someone wants to do more fine-tuning of the timing. | ||||||
|  |   nrf_pwm_configure(pwm, NRF_PWM_CLK_16MHz, NRF_PWM_MODE_UP, CTOPVAL); | ||||||
|  |  | ||||||
|  |   // Disable loops, we want the sequence to repeat only once | ||||||
|  |   nrf_pwm_loop_set(pwm, 0); | ||||||
|  |  | ||||||
|  |   // On the "Common" setting the PWM uses the same pattern for the | ||||||
|  |   // for supported sequences. The pattern is stored on half-word of 16bits | ||||||
|  |   nrf_pwm_decoder_set(pwm, PWM_DECODER_LOAD_Common, PWM_DECODER_MODE_RefreshCount); | ||||||
|  |  | ||||||
|  |   // The following settings are ignored with the current config. | ||||||
|  |   nrf_pwm_seq_refresh_set(pwm, 0, 0); | ||||||
|  |   nrf_pwm_seq_end_delay_set(pwm, 0, 0); | ||||||
|  |  | ||||||
|  |   // The Neopixel implementation is a blocking algorithm. DMA | ||||||
|  |   // allows for non-blocking operation. To "simulate" a blocking | ||||||
|  |   // operation we enable the interruption for the end of sequence | ||||||
|  |   // and block the execution thread until the event flag is set by | ||||||
|  |   // the peripheral. | ||||||
|  |   //    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 }); | ||||||
|  |  | ||||||
|  |   // Enable the PWM | ||||||
|  |   nrf_pwm_enable(pwm); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void neopixel_teardown(void) | ||||||
|  | { | ||||||
|  |   pwm_teardown(NRF_PWM2); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // write 3 bytes color to a built-in neopixel | ||||||
|  | void neopixel_write (uint8_t *pixels) | ||||||
|  | { | ||||||
|  |   uint16_t pos = 0;    // bit position | ||||||
|  |   for ( uint16_t n = 0; n < NEO_NUMBYTE; n++ ) | ||||||
|  |   { | ||||||
|  |     uint8_t pix = pixels[n]; | ||||||
|  |  | ||||||
|  |     for ( uint8_t mask = 0x80; mask > 0; mask >>= 1 ) | ||||||
|  |     { | ||||||
|  |       pixels_pattern[pos] = (pix & mask) ? MAGIC_T1H : MAGIC_T0H; | ||||||
|  |       pos++; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // Zero padding to indicate the end of sequence | ||||||
|  |   pixels_pattern[++pos] = 0 | (0x8000);    // Seq end | ||||||
|  |   pixels_pattern[++pos] = 0 | (0x8000);    // Seq end | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   NRF_PWM_Type* pwm = NRF_PWM2; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   nrf_pwm_seq_ptr_set(pwm, 0, pixels_pattern); | ||||||
|  |   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); | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  |  | ||||||
|   | |||||||
| @@ -14,6 +14,7 @@ | |||||||
|  |  | ||||||
| #include <stdbool.h> | #include <stdbool.h> | ||||||
| #include <stdint.h> | #include <stdint.h> | ||||||
|  | #include <string.h> | ||||||
| #include "nrf_gpio.h" | #include "nrf_gpio.h" | ||||||
|  |  | ||||||
| #if defined BOARD_FEATHER_NRF52840_EXPRESS | #if defined BOARD_FEATHER_NRF52840_EXPRESS | ||||||
| @@ -71,6 +72,10 @@ void led_pwm_enable(uint32_t led_pin); | |||||||
|  |  | ||||||
| void led_red_blink_fast(bool enable); | void led_red_blink_fast(bool enable); | ||||||
|  |  | ||||||
|  | #ifdef LED_NEOPIXEL | ||||||
|  |   void neopixel_write(uint8_t *pixels); | ||||||
|  | #endif | ||||||
|  |  | ||||||
| //--------------------------------------------------------------------+ | //--------------------------------------------------------------------+ | ||||||
| // BUTTONS | // BUTTONS | ||||||
| //--------------------------------------------------------------------+ | //--------------------------------------------------------------------+ | ||||||
|   | |||||||
| @@ -46,6 +46,8 @@ | |||||||
| #include "tusb.h" | #include "tusb.h" | ||||||
| #include "usb_desc.h" | #include "usb_desc.h" | ||||||
|  |  | ||||||
|  | #include "boards.h" | ||||||
|  |  | ||||||
| //--------------------------------------------------------------------+ | //--------------------------------------------------------------------+ | ||||||
| // MACRO TYPEDEF CONSTANT ENUM DECLARATION | // MACRO TYPEDEF CONSTANT ENUM DECLARATION | ||||||
| //--------------------------------------------------------------------+ | //--------------------------------------------------------------------+ | ||||||
| @@ -155,11 +157,17 @@ void usb_teardown(void) | |||||||
| //--------------------------------------------------------------------+ | //--------------------------------------------------------------------+ | ||||||
| void tud_mount_cb(void) | void tud_mount_cb(void) | ||||||
| { | { | ||||||
|  | #ifdef LED_NEOPIXEL | ||||||
|  |   uint8_t grb[] = { 255, 0, 0 }; | ||||||
|  |   neopixel_write(grb); | ||||||
|  | #endif | ||||||
| } | } | ||||||
|  |  | ||||||
| void tud_umount_cb(void) | void tud_umount_cb(void) | ||||||
| { | { | ||||||
|  | #ifdef LED_NEOPIXEL | ||||||
|  |   uint8_t grb[] = { 0, 255, 0 }; | ||||||
|  |   neopixel_write(grb); | ||||||
|  | #endif | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user