pwm driver ws2812 meet 'No space in execution regions'

Hi.
SDK:11.0


Our product is ready to add a ws2812 on the basis of the original peripheral and drive the implementation through hardware pwm. The lamp has 30 beads, each requiring 3byte to achieve RGB three colors. Therefore, a ws2812 requires 720 bytes of data. I am experiencing insufficient IRAM while loading the PWM array. Is there any other optimization I can do to enable 720byte data to be written to drive the entire strip each time ’nrf_drv_pwm_simple_playback‘ is called.

https://www.mouser.com/pdfDocs/WS2812B-2020_V10_EN_181106150240761.pdf 



#define WS2812_T1H                  14 | 0x8000   // In each value, the most significant bit (15)determines the polarity of the output and theothers (14-0) compose the 15-bit value
#define WS2812_T0H                  6  | 0x8000

#define LED_MATRIX_WIDTH  30
#define LED_MATRIX_HEIGHT 1
#define WS2812_PIN  6

#define LED_MATRIX_TOTAL_BYTE_WIDTH	 LED_MATRIX_WIDTH * LED_MATRIX_HEIGHT * 3
#define LED_MATRIX_TOTAL_BIT_WIDTH	 LED_MATRIX_TOTAL_BYTE_WIDTH * 8

static rgb_color_t led_matrix_buffer[LED_MATRIX_WIDTH][LED_MATRIX_HEIGHT];

static nrf_drv_pwm_t m_pwm2 = NRF_DRV_PWM_INSTANCE(0);
static nrf_pwm_values_individual_t pwm_duty_cycle_values[LED_MATRIX_TOTAL_BIT_WIDTH];

static nrf_pwm_sequence_t pwm_sequence =
{
    .values.p_individual = pwm_duty_cycle_values,
    .length          = (sizeof(pwm_duty_cycle_values) / sizeof(uint16_t)),
    .repeats         = 0,
    .end_delay       = 0
};

#define USED_PWM(idx) (1UL << idx)
static uint8_t m_used = 0;
static uint32_t pwm_init(void)
{
	    nrf_drv_pwm_config_t const pwm_config =
    {
        .output_pins =
        {
            NRF_DRV_PWM_PIN_NOT_USED, // channel 0
            WS2812_PIN ,             // channel 1
            NRF_DRV_PWM_PIN_NOT_USED,             // channel 2
            NRF_DRV_PWM_PIN_NOT_USED,             // channel 3
        },
        .irq_priority = APP_IRQ_PRIORITY_LOW,
        .base_clock   = NRF_PWM_CLK_16MHz,
        .count_mode   = NRF_PWM_MODE_UP,
				// WS2812 protocol requires a 800 kHz PWM frequency. PWM Top value = 20 and Base Clock = 16 MHz achieves this
        .top_value    = 20,
        .load_mode    = NRF_PWM_LOAD_INDIVIDUAL,
        .step_mode    = NRF_PWM_STEP_AUTO
    };
		APP_ERROR_CHECK(nrf_drv_pwm_init(&m_pwm2, &pwm_config, pwm_handler)); m_used |= USED_PWM(0);
    //return nrf_drv_pwm_init(&m_pwm2, &pwm_config, pwm_handler);
		
}


static void convert_rgb_to_pwm_sequence(void)
{
    uint8_t * ptr = (uint8_t *)led_matrix_buffer;
    uint32_t i = 0;
    for(int led = 0; led < LED_MATRIX_TOTAL_BYTE_WIDTH; led++)
    {
        for(int bit = 7; bit >= 0; bit--)
        {
            uint8_t code = (*ptr >> bit) & 0x01;
            uint16_t pwm_value = 0;
            if(code == 1)
            {
                pwm_value = WS2812_T1H;
            }
            else
            {
                pwm_value = WS2812_T0H;
            }
            pwm_duty_cycle_values[i++].channel_1 = pwm_value;
        }
        ptr++;
    }
}

uint32_t drv_ws2812_init(void)
{   
		volatile uint32_t length = sizeof(pwm_duty_cycle_values) ;
    volatile uint32_t size = sizeof(led_matrix_buffer);
    memset(led_matrix_buffer, 0x00, sizeof(led_matrix_buffer));   
    return pwm_init();
}

uint32_t drv_ws2812_display(void)
{
    if(!pwm_sequencue_finished) 
    {
        return NRF_ERROR_BUSY;
    }
    convert_rgb_to_pwm_sequence();
    pwm_sequencue_finished = false;
    (void)nrf_drv_pwm_simple_playback(&m_pwm2, &pwm_sequence, 1, NRF_DRV_PWM_FLAG_STOP);
}


Best regard!

Related