add neopixel support
This commit is contained in:
		
							
								
								
									
										134
									
								
								src/boards.c
									
									
									
									
									
								
							
							
						
						
									
										134
									
								
								src/boards.c
									
									
									
									
									
								
							@@ -35,6 +35,7 @@
 | 
			
		||||
/**************************************************************************/
 | 
			
		||||
 | 
			
		||||
#include "boards.h"
 | 
			
		||||
#include "nrf_pwm.h"
 | 
			
		||||
#include "app_scheduler.h"
 | 
			
		||||
#include "app_timer.h"
 | 
			
		||||
 | 
			
		||||
@@ -83,7 +84,11 @@ void board_init(void)
 | 
			
		||||
 | 
			
		||||
// use neopixel for use enumeration
 | 
			
		||||
#ifdef LED_NEOPIXEL
 | 
			
		||||
  extern void neopixel_init(void);
 | 
			
		||||
  neopixel_init();
 | 
			
		||||
 | 
			
		||||
  uint8_t grb[] = { 0, 255, 0 };
 | 
			
		||||
  neopixel_write(grb);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  // Init scheduler
 | 
			
		||||
@@ -98,6 +103,11 @@ void board_teardown(void)
 | 
			
		||||
  // Disable and reset PWM for LED
 | 
			
		||||
  led_pwm_teardown(LED_RED);
 | 
			
		||||
 | 
			
		||||
#ifdef LED_NEOPIXEL
 | 
			
		||||
  extern void neopixel_teardown(void);
 | 
			
		||||
  neopixel_teardown();
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  led_off(LED_BLUE);
 | 
			
		||||
  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 );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
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)
 | 
			
		||||
{
 | 
			
		||||
  NRF_PWM_Type* pwm    = (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;
 | 
			
		||||
  pwm_teardown ((led_pin == LED_RED) ? NRF_PWM0 : NRF_PWM1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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 <stdint.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include "nrf_gpio.h"
 | 
			
		||||
 | 
			
		||||
#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);
 | 
			
		||||
 | 
			
		||||
#ifdef LED_NEOPIXEL
 | 
			
		||||
  void neopixel_write(uint8_t *pixels);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
//--------------------------------------------------------------------+
 | 
			
		||||
// BUTTONS
 | 
			
		||||
//--------------------------------------------------------------------+
 | 
			
		||||
 
 | 
			
		||||
@@ -46,6 +46,8 @@
 | 
			
		||||
#include "tusb.h"
 | 
			
		||||
#include "usb_desc.h"
 | 
			
		||||
 | 
			
		||||
#include "boards.h"
 | 
			
		||||
 | 
			
		||||
//--------------------------------------------------------------------+
 | 
			
		||||
// MACRO TYPEDEF CONSTANT ENUM DECLARATION
 | 
			
		||||
//--------------------------------------------------------------------+
 | 
			
		||||
@@ -155,11 +157,17 @@ void usb_teardown(void)
 | 
			
		||||
//--------------------------------------------------------------------+
 | 
			
		||||
void tud_mount_cb(void)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
#ifdef LED_NEOPIXEL
 | 
			
		||||
  uint8_t grb[] = { 255, 0, 0 };
 | 
			
		||||
  neopixel_write(grb);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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