Improved memory checks

This commit is contained in:
mrfaptastic 2020-07-29 10:44:38 +01:00
parent 75136c59e1
commit 9a5ed4db9e
5 changed files with 187 additions and 173 deletions

View file

@ -76,10 +76,10 @@ bool RGB64x32MatrixPanel_I2S_DMA::allocateDMAmemory()
if (double_buffering_enabled) {
Serial.println("DOUBLE FRAME BUFFERS / DOUBLE BUFFERING IS ENABLED. DOUBLE THE RAM REQUIRED!");
}
/*
Serial.println("DMA memory blocks available before any malloc's: ");
heap_caps_print_heap_info(MALLOC_CAP_DMA);
*/
Serial.printf("FYI: Size of an ESP32 DMA linked list descriptor (lldesc_t) is %d bytes\r\n", sizeof(lldesc_t));
Serial.printf("We're going to need %d bytes of SRAM just for the frame buffer(s).\r\n", _frame_buffer_memory_required);
@ -87,37 +87,53 @@ bool RGB64x32MatrixPanel_I2S_DMA::allocateDMAmemory()
#endif
// Can we fit the framebuffer into the single DMA capable memory block available?
if ( heap_caps_get_largest_free_block(MALLOC_CAP_DMA) >= _frame_buffer_memory_required ) { // YES - SIMPLE
// Allocate the framebuffer memory, fail if we can even do this
matrix_framebuffer_malloc_1 = (frameStruct *)heap_caps_malloc(_frame_buffer_memory_required, MALLOC_CAP_DMA);
if ( !matrix_framebuffer_malloc_1 ) {
#if SERIAL_DEBUG
Serial.println("ERROR: Couldn't malloc matrix_framebuffer_malloc_1! Critical fail.\r\n");
#endif
return false;
}
_total_dma_capable_memory_reserved += _frame_buffer_memory_required;
}
#ifdef SPLIT_MEMORY_MODE
Serial.println("SPLIT MEMORY MODE ENABLED!");
if ( heap_caps_get_largest_free_block(MALLOC_CAP_DMA) < _frame_buffer_memory_required ) {
#if SERIAL_DEBUG
Serial.print("Rows per frame (overall): "); Serial.println(ROWS_PER_FRAME, DEC);
Serial.print("Rows per split framebuffer malloc: "); Serial.println(SPLIT_MEMORY_ROWS_PER_FRAME, DEC);
Serial.printf("######### Insufficent memory for requested resolution. Reduce MATRIX_COLOR_DEPTH and try again.\r\n\tAdditional %d bytes of memory required.\r\n\r\n", (_frame_buffer_memory_required-heap_caps_get_largest_free_block(MALLOC_CAP_DMA)) );
#endif
return false;
}
// Can we fit the framebuffer into the single DMA capable memory block available?
if ( heap_caps_get_largest_free_block(MALLOC_CAP_DMA) >= _frame_buffer_memory_required ) { // YES - SIMPLE
// Allocate the framebuffer memory, fail if we can even do this
// Allocate the framebuffer 1 memory, fail if we can even do this
matrix_framebuffer_malloc_1 = (frameStruct *)heap_caps_malloc(_frame_buffer_memory_required, MALLOC_CAP_DMA);
if ( matrix_framebuffer_malloc_1 == NULL ) {
#if SERIAL_DEBUG
Serial.println("ERROR: Couldn't malloc matrix_framebuffer_malloc_1! Critical fail.\r\n");
#endif
return false;
}
_total_dma_capable_memory_reserved += _frame_buffer_memory_required;
// SPLIT MEMORY MODE
#ifdef SPLIT_MEMORY_MODE
Serial.println("SPLIT MEMORY MODE ENABLED!");
#if SERIAL_DEBUG
Serial.print("Rows per frame (overall): "); Serial.println(ROWS_PER_FRAME, DEC);
Serial.print("Rows per split framebuffer malloc: "); Serial.println(SPLIT_MEMORY_ROWS_PER_FRAME, DEC);
#endif
// Can we fit the framebuffer into the single DMA capable memory block available?
// Can we fit the framebuffer into the single DMA capable memory block available?
if ( heap_caps_get_largest_free_block(MALLOC_CAP_DMA) < _frame_buffer_memory_required ) {
#if SERIAL_DEBUG
Serial.printf("######### Insufficent memory for second framebuffer for requested resolution. Reduce MATRIX_COLOR_DEPTH and try again.\r\n\tAdditional %d bytes of memory required.\r\n\r\n", (_frame_buffer_memory_required-heap_caps_get_largest_free_block(MALLOC_CAP_DMA)) );
#endif
return false;
}
// Allocate the framebuffer 2 memory, fail if we can even do this
matrix_framebuffer_malloc_2 = (frameStruct *)heap_caps_malloc(_frame_buffer_memory_required, MALLOC_CAP_DMA);
if ( !matrix_framebuffer_malloc_2 ) {
if ( matrix_framebuffer_malloc_2 == NULL ) {
#if SERIAL_DEBUG
Serial.println("ERROR: Couldn't malloc matrix_framebuffer_malloc_2! Critical fail.\r\n");
#endif
@ -126,7 +142,7 @@ bool RGB64x32MatrixPanel_I2S_DMA::allocateDMAmemory()
}
_total_dma_capable_memory_reserved += _frame_buffer_memory_required;
}
#endif
@ -245,6 +261,15 @@ bool RGB64x32MatrixPanel_I2S_DMA::allocateDMAmemory()
Serial.printf("DMA Memory Available: %d bytes total. Largest free block: %d bytes.\r\n", heap_caps_get_free_size(MALLOC_CAP_DMA), heap_caps_get_largest_free_block(MALLOC_CAP_DMA));
Serial.printf("General RAM Available: %d bytes total. Largest free block: %d bytes.\r\n", heap_caps_get_free_size(MALLOC_CAP_DEFAULT), heap_caps_get_largest_free_block(MALLOC_CAP_DEFAULT));
#if SERIAL_DEBUG
Serial.println("DMA memory blocks available after malloc's: ");
heap_caps_print_heap_info(MALLOC_CAP_DMA);
delay(1000);
#endif
return true;
} // end initMatrixDMABuffer()
@ -358,10 +383,12 @@ void RGB64x32MatrixPanel_I2S_DMA::configureDMA(int r1_pin, int g1_pin, int b1_
Serial.println("configureDMA(): DMA configuration completed on I2S1.\r\n");
#endif
#if SERIAL_DEBUG
Serial.println("DMA Memory Map after allocations: ");
heap_caps_print_heap_info(MALLOC_CAP_DMA);
#endif
#if SERIAL_DEBUG
Serial.println("DMA Memory Map after DMA LL allocations: ");
heap_caps_print_heap_info(MALLOC_CAP_DMA);
delay(1000);
#endif
// Just os we know
everything_OK = true;
@ -375,11 +402,20 @@ void RGB64x32MatrixPanel_I2S_DMA::configureDMA(int r1_pin, int g1_pin, int b1_
/* Update a specific co-ordinate in the DMA buffer */
void RGB64x32MatrixPanel_I2S_DMA::updateMatrixDMABuffer(int16_t x_coord, int16_t y_coord, uint8_t red, uint8_t green, uint8_t blue)
{
if ( !everything_OK ) {
if ( !everything_OK )
assert("DMA configuration in begin() not performed or completed successfully.");
#if SERIAL_DEBUG
Serial.println("Cannot updateMatrixDMABuffer as setup failed!");
#endif
return;
}
#ifdef SPLIT_MEMORY_MODE
#ifdef SERIAL_DEBUG
int tmp_y_coord = y_coord;
#endif
#endif
/* 1) Check that the co-ordinates are within range, or it'll break everything big time.
* Valid co-ordinates are from 0 to (MATRIX_XXXX-1)
@ -410,11 +446,11 @@ void RGB64x32MatrixPanel_I2S_DMA::updateMatrixDMABuffer(int16_t x_coord, int16_t
#ifdef SPLIT_MEMORY_MODE
if (y_coord >= SPLIT_MEMORY_ROWS_PER_FRAME ) {
p = &matrix_framebuffer_malloc_2[back_buffer_id].rowdata[(y_coord-SPLIT_MEMORY_ROWS_PER_FRAME)].rowbits[color_depth_idx]; //matrixUpdateFrames location to write to uint16_t's
}
#ifdef SERIAL_DEBUG
// Serial.printf("Using framebuffer_malloc_2. y-coord: %d, matrix row offset: %d \r\n", tmp_y_coord, (y_coord-SPLIT_MEMORY_ROWS_PER_FRAME) );
#endif
#ifdef SERIAL_DEBUG
// Serial.printf("fb_malloc_2. y-coord: %d, calc. offset: %d \r\n", tmp_y_coord, (y_coord-SPLIT_MEMORY_ROWS_PER_FRAME) );
#endif
}
#endif
@ -467,19 +503,18 @@ void RGB64x32MatrixPanel_I2S_DMA::updateMatrixDMABuffer(int16_t x_coord, int16_t
if((x_coord) >= lsbBrightness) v|=BIT_OE; // For Brightness
}
/* When using the Adafruit drawPixel, we only have one pixel co-ordinate and colour to draw (duh)
* so we can't paint a top and bottom half (or whatever row split the panel is) at the same time.
* Need to be smart and check the DMA buffer to see what the other half thinks (pun intended)
* and persist this when we refresh.
/* When using the drawPixel, we are obviously only changing the value of one x,y position,
* however, the HUB75 is wired up such that it is always painting TWO lines at the same time
* and this reflects the parallel in-DMA-memory data structure of uint16_t's that are getting
* pumped out at high speed.
*
* So we need to ensure we persist the bits (8 of them) of the uint16_t for the row we aren't changing.
*
* The DMA buffer order has also been reversed (refer to the last code in this function)
* so we have to check for this and check the correct position of the MATRIX_DATA_STORAGE_TYPE
* data.
*/
int16_t tmp_x_coord = x_coord;
int tmp_x_coord = x_coord;
if(x_coord%2)
{
tmp_x_coord -= 1;
@ -491,12 +526,9 @@ void RGB64x32MatrixPanel_I2S_DMA::updateMatrixDMABuffer(int16_t x_coord, int16_t
{ // Need to copy what the RGB status is for the bottom pixels
// Set the color of the pixel of interest
if (green & mask)
v|=BIT_G1;
if (blue & mask)
v|=BIT_B1;
if (red & mask)
v|=BIT_R1;
if (green & mask) { v|=BIT_G1; }
if (blue & mask) { v|=BIT_B1; }
if (red & mask) { v|=BIT_R1; }
// Persist what was painted to the other half of the frame equiv. pixel
if (p->data[tmp_x_coord] & BIT_R2)
@ -512,12 +544,9 @@ void RGB64x32MatrixPanel_I2S_DMA::updateMatrixDMABuffer(int16_t x_coord, int16_t
{ // Do it the other way around
// Color to set
if (red & mask)
v|=BIT_R2;
if (green & mask)
v|=BIT_G2;
if (blue & mask)
v|=BIT_B2;
if (red & mask) { v|=BIT_R2; }
if (green & mask) { v|=BIT_G2; }
if (blue & mask) { v|=BIT_B2; }
// Copy
if (p->data[tmp_x_coord] & BIT_R1)
@ -531,10 +560,6 @@ void RGB64x32MatrixPanel_I2S_DMA::updateMatrixDMABuffer(int16_t x_coord, int16_t
} // paint
//Serial.printf("x: %d, y: %d ", x_coord, y_coord );
//Serial.println(v, BIN);
// 16 bit parallel mode
//Save the calculated value to the bitplane memory in reverse order to account for I2S Tx FIFO mode1 ordering
if(x_coord%2){
@ -545,19 +570,14 @@ void RGB64x32MatrixPanel_I2S_DMA::updateMatrixDMABuffer(int16_t x_coord, int16_t
} // color depth loop (8)
//Show our work!
//i2s_parallel_flip_to_buffer(&I2S1, backbuf_id);
// If we've linked the DMA output to the same backbuf_id that this function is
// currently writing too, then the output will be immediate. Else: flipDMABuffer(), then showDMABuffer()
} // updateDMABuffer
} // updateMatrixDMABuffer (specific co-ords change)
/* Update the entire buffer with a single specific colour - quicker */
void RGB64x32MatrixPanel_I2S_DMA::updateMatrixDMABuffer(uint8_t red, uint8_t green, uint8_t blue)
{
if ( !everything_OK ) return;
for (unsigned int matrix_frame_parallel_row = 0; matrix_frame_parallel_row < ROWS_PER_FRAME; matrix_frame_parallel_row++) // half height - 16 iterations
{
for(int color_depth_idx=0; color_depth_idx<PIXEL_COLOR_DEPTH_BITS; color_depth_idx++) // color depth - 8 iterations
@ -572,101 +592,86 @@ void RGB64x32MatrixPanel_I2S_DMA::updateMatrixDMABuffer(uint8_t red, uint8_t gre
p = &matrix_framebuffer_malloc_2[back_buffer_id].rowdata[(matrix_frame_parallel_row-SPLIT_MEMORY_ROWS_PER_FRAME)].rowbits[color_depth_idx]; //matrixUpdateFrames location to write to uint16_t's
#ifdef SERIAL_DEBUG
// Serial.printf("Using framebuffer_malloc_2. Row %d = Offset %d\r\n", matrix_frame_parallel_row, (matrix_frame_parallel_row-SPLIT_MEMORY_ROWS_PER_FRAME) );
//Serial.printf("Using framebuffer_malloc_2. Row %d = Offset %d\r\n", matrix_frame_parallel_row, (matrix_frame_parallel_row-SPLIT_MEMORY_ROWS_PER_FRAME) );
#endif
}
else
{
#ifdef SERIAL_DEBUG
// Serial.printf("Using framebuffer_malloc_1. Row %d\r\n", matrix_frame_parallel_row );
#endif
}
#endif
for(int x_coord=0; x_coord < MATRIX_WIDTH; x_coord++) // row pixel width 64 iterations
{
int v=0; // the output bitstream
int v=0; // the output bitstream
// if there is no latch to hold address, output ADDX lines directly to GPIO and latch data at end of cycle
int gpioRowAddress = matrix_frame_parallel_row;
// if there is no latch to hold address, output ADDX lines directly to GPIO and latch data at end of cycle
int gpioRowAddress = matrix_frame_parallel_row;
// normally output current rows ADDX, special case for LSB, output previous row's ADDX (as previous row is being displayed for one latch cycle)
if(color_depth_idx == 0)
gpioRowAddress = matrix_frame_parallel_row-1;
// normally output current rows ADDX, special case for LSB, output previous row's ADDX (as previous row is being displayed for one latch cycle)
if(color_depth_idx == 0)
gpioRowAddress = matrix_frame_parallel_row-1;
if (gpioRowAddress & 0x01) v|=BIT_A; // 1
if (gpioRowAddress & 0x02) v|=BIT_B; // 2
if (gpioRowAddress & 0x04) v|=BIT_C; // 4
if (gpioRowAddress & 0x08) v|=BIT_D; // 8
if (gpioRowAddress & 0x10) v|=BIT_E; // 16
if (gpioRowAddress & 0x01) v|=BIT_A; // 1
if (gpioRowAddress & 0x02) v|=BIT_B; // 2
if (gpioRowAddress & 0x04) v|=BIT_C; // 4
if (gpioRowAddress & 0x08) v|=BIT_D; // 8
if (gpioRowAddress & 0x10) v|=BIT_E; // 16
/* ORIG
// need to disable OE after latch to hide row transition
if((x_coord) == 0) v|=BIT_OE;
/* ORIG
// need to disable OE after latch to hide row transition
if((x_coord) == 0) v|=BIT_OE;
// drive latch while shifting out last bit of RGB data
if((x_coord) == PIXELS_PER_LATCH-1) v|=BIT_LAT;
// drive latch while shifting out last bit of RGB data
if((x_coord) == PIXELS_PER_LATCH-1) v|=BIT_LAT;
// need to turn off OE one clock before latch, otherwise can get ghosting
if((x_coord)==PIXELS_PER_LATCH-1) v|=BIT_OE;
*/
// need to turn off OE one clock before latch, otherwise can get ghosting
if((x_coord)==PIXELS_PER_LATCH-1) v|=BIT_OE;
*/
// need to disable OE after latch to hide row transition
if((x_coord) == 0 ) v|=BIT_OE;
// need to disable OE after latch to hide row transition
if((x_coord) == 0 ) v|=BIT_OE;
// drive latch while shifting out last bit of RGB data
if((x_coord) == PIXELS_PER_ROW-1) v|=BIT_LAT;
// drive latch while shifting out last bit of RGB data
if((x_coord) == PIXELS_PER_ROW-1) v|=BIT_LAT;
// need to turn off OE one clock before latch, otherwise can get ghosting
if((x_coord)==PIXELS_PER_ROW-2) v|=BIT_OE;
// need to turn off OE one clock before latch, otherwise can get ghosting
if((x_coord)==PIXELS_PER_ROW-2) v|=BIT_OE;
// turn off OE after brightness value is reached when displaying MSBs
// MSBs always output normal brightness
// LSB (!color_depth_idx) outputs normal brightness as MSB from previous row is being displayed
if((color_depth_idx > lsbMsbTransitionBit || !color_depth_idx) && ((x_coord) >= brightness)) v|=BIT_OE; // For Brightness
// turn off OE after brightness value is reached when displaying MSBs
// MSBs always output normal brightness
// LSB (!color_depth_idx) outputs normal brightness as MSB from previous row is being displayed
if((color_depth_idx > lsbMsbTransitionBit || !color_depth_idx) && ((x_coord) >= brightness)) v|=BIT_OE; // For Brightness
// special case for the bits *after* LSB through (lsbMsbTransitionBit) - OE is output after data is shifted, so need to set OE to fractional brightness
if(color_depth_idx && color_depth_idx <= lsbMsbTransitionBit) {
// divide brightness in half for each bit below lsbMsbTransitionBit
int lsbBrightness = brightness >> (lsbMsbTransitionBit - color_depth_idx + 1);
if((x_coord) >= lsbBrightness) v|=BIT_OE; // For Brightness
}
// special case for the bits *after* LSB through (lsbMsbTransitionBit) - OE is output after data is shifted, so need to set OE to fractional brightness
if(color_depth_idx && color_depth_idx <= lsbMsbTransitionBit) {
// divide brightness in half for each bit below lsbMsbTransitionBit
int lsbBrightness = brightness >> (lsbMsbTransitionBit - color_depth_idx + 1);
if((x_coord) >= lsbBrightness) v|=BIT_OE; // For Brightness
}
// Top and bottom matrix MATRIX_ROWS_IN_PARALLEL half colours
if (green & mask) { v|=BIT_G1; v|=BIT_R2; }
if (blue & mask) { v|=BIT_B1; v|=BIT_G2; }
if (red & mask) { v|=BIT_R1; v|=BIT_B2; }
// Top half colours
if (green & mask)
v|=BIT_G1;
if (blue & mask)
v|=BIT_B1;
if (red & mask)
v|=BIT_R1;
// 16 bit parallel mode
//Save the calculated value to the bitplane memory in reverse order to account for I2S Tx FIFO mode1 ordering
if(x_coord%2) {
p->data[(x_coord)-1] = v;
} else {
p->data[(x_coord)+1] = v;
} // end reordering
// Bottom half colours
if (red & mask)
v|=BIT_R2;
if (green & mask)
v|=BIT_G2;
if (blue & mask)
v|=BIT_B2;
// 16 bit parallel mode
//Save the calculated value to the bitplane memory in reverse order to account for I2S Tx FIFO mode1 ordering
if(x_coord%2)
{
p->data[(x_coord)-1] = v;
} else {
p->data[(x_coord)+1] = v;
} // end reordering
} // end x_coord iteration
} // end x_coord iteration
} // colour depth loop (8)
} // end row iteration
//Show our work!
//i2s_parallel_flip_to_buffer(&I2S1, backbuf_id);
// If we've linked the DMA output to the same backbuf_id that this function is
// currently writing too, then the output will be immediate. Else: flipDMABuffer(), then showDMABuffer()
} // updateDMABuffer
} // updateMatrixDMABuffer (full frame paint)

View file

@ -35,7 +35,7 @@
*
*/
#ifndef MATRIX_HEIGHT
#define MATRIX_HEIGHT 32 //64
#define MATRIX_HEIGHT 32
#endif
#ifndef MATRIX_WIDTH
@ -210,6 +210,11 @@ class RGB64x32MatrixPanel_I2S_DMA : public GFX {
showDMABuffer(); // show backbuf_id of 0
#if SERIAL_DEBUG
if (!everything_OK)
Serial.println("RGB64x32MatrixPanel_I2S_DMA::begin() failed.");
#endif
return everything_OK;
}

View file

@ -64,7 +64,7 @@ A [typical RGB panel available for purchase](https://www.aliexpress.com/item/256
## Can I chain panels or use with larger panels?
Yes you can. If you want to use with a 64x64 pixel panel you MUST configure a valid *E_PIN* to your ESP32 and connect it to the E pin of the HUB75 panel!
Yes you can. If you want to use with a 64x64 pixel panel (typically a HUB75*E* panel) you MUST configure a valid *E_PIN* to your ESP32 and connect it to the E pin of the HUB75 panel! Hence the 'E' in 'HUB75E'
This library has only been tested with a 64 pixel (wide) and 32 (high) RGB panel. Theoretically, if you want to chain two of these horizontally to make a 128x32 panel you can do so with the cable and then set the MATRIX_WIDTH to '128'.

View file

@ -29,9 +29,11 @@
#include "driver/periph_ctrl.h"
#include "soc/io_mux_reg.h"
#include "rom/lldesc.h"
#include "esp_heap_caps.h"
//#include "esp_heap_caps.h"
#include "esp32_i2s_parallel.h"
#define DMA_MAX (4096-4)
typedef struct {
volatile lldesc_t *dmadesc_a, *dmadesc_b;
int desccount_a, desccount_b;
@ -61,9 +63,7 @@ static void IRAM_ATTR i2s_isr(void* arg) {
if(shiftCompleteCallback)
shiftCompleteCallback();
}
#define DMA_MAX (4096-4)
/*
//Calculate the amount of dma descs needed for a buffer desc
static int calc_needed_dma_descs_for(i2s_parallel_buffer_desc_t *desc) {
int ret=0;
@ -102,8 +102,10 @@ static void fill_dma_desc(volatile lldesc_t *dmadesc, i2s_parallel_buffer_desc_t
printf("fill_dma_desc: filled %d descriptors\n", n);
}
*/
// size must be less than DMA_MAX - need to handle breaking long transfer into two descriptors before call
// DMA_MAX by the way is the maximum data packet size you can hold in one chunk
void link_dma_desc(volatile lldesc_t *dmadesc, volatile lldesc_t *prevdmadesc, void *memory, size_t size) {
if(size > DMA_MAX) size = DMA_MAX;
@ -128,7 +130,6 @@ static void gpio_setup_out(int gpio, int sig) {
gpio_matrix_out(gpio, sig, false, false);
}
static void dma_reset(i2s_dev_t *dev) {
dev->lc_conf.in_rst=1; dev->lc_conf.in_rst=0;
dev->lc_conf.out_rst=1; dev->lc_conf.out_rst=0;
@ -147,14 +148,14 @@ void i2s_parallel_setup_without_malloc(i2s_dev_t *dev, const i2s_parallel_config
sig_data_base=I2S0O_DATA_OUT0_IDX;
sig_clk=I2S0O_WS_OUT_IDX;
} else {
printf("Setting up i2s parallel mode in %d bit mode!\n", cfg->bits);
if (cfg->bits==I2S_PARALLEL_BITS_32) {
sig_data_base=I2S1O_DATA_OUT0_IDX;
} else if (cfg->bits==I2S_PARALLEL_BITS_16) {
//Because of... reasons... the 16-bit values for i2s1 appear on d8...d23
printf("Setting up i2s parallel mode in 16 bit mode!");
sig_data_base=I2S1O_DATA_OUT8_IDX;
} else { // I2S_PARALLEL_BITS_8
printf("Setting up i2s parallel mode in 8 bit mode -> https://www.esp32.com/viewtopic.php?f=17&t=3188 | https://www.esp32.com/viewtopic.php?f=13&t=3256");
//printf("Setting up i2s parallel mode in %d bit mode -> https://www.esp32.com/viewtopic.php?f=17&t=3188 | https://www.esp32.com/viewtopic.php?f=13&t=3256", 8);
sig_data_base=I2S1O_DATA_OUT0_IDX;
}
sig_clk=I2S1O_WS_OUT_IDX;
@ -251,7 +252,7 @@ void i2s_parallel_setup_without_malloc(i2s_dev_t *dev, const i2s_parallel_config
// allocate a level 1 intterupt: lowest priority, as ISR isn't urgent and may take a long time to complete
esp_intr_alloc(ETS_I2S1_INTR_SOURCE, (int)(ESP_INTR_FLAG_IRAM | ESP_INTR_FLAG_LEVEL1), i2s_isr, NULL, NULL);
//Start dma on front buffer
//Start dma on front buffer (buffer a)
dev->lc_conf.val=I2S_OUT_DATA_BURST_EN | I2S_OUTDSCR_BURST_EN | I2S_OUT_DATA_BURST_EN;
dev->out_link.addr=((uint32_t)(&st->dmadesc_a[0]));
dev->out_link.start=1;
@ -281,4 +282,5 @@ bool i2s_parallel_is_previous_buffer_free() {
return previousBufferFree;
}
#endif

View file

@ -13,7 +13,7 @@ extern "C" {
#include "rom/lldesc.h"
typedef enum {
I2S_PARALLEL_BITS_8=8, // BUG: Doesn't work.
I2S_PARALLEL_BITS_8=8,
I2S_PARALLEL_BITS_16=16,
I2S_PARALLEL_BITS_32=32,
} i2s_parallel_cfg_bits_t;
@ -29,18 +29,20 @@ typedef struct {
int clkspeed_hz;
i2s_parallel_cfg_bits_t bits;
i2s_parallel_buffer_desc_t *bufa;
i2s_parallel_buffer_desc_t *bufb;
i2s_parallel_buffer_desc_t *bufb; // only used with double buffering
int desccount_a;
int desccount_b;
int desccount_b; // only used with double buffering
lldesc_t * lldesc_a;
lldesc_t * lldesc_b;
lldesc_t * lldesc_b; // only used with double buffering
} i2s_parallel_config_t;
void i2s_parallel_setup(i2s_dev_t *dev, const i2s_parallel_config_t *cfg);
void i2s_parallel_setup_without_malloc(i2s_dev_t *dev, const i2s_parallel_config_t *cfg);
void link_dma_desc(volatile lldesc_t *dmadesc, volatile lldesc_t *prevdmadesc, void *memory, size_t size);
void i2s_parallel_flip_to_buffer(i2s_dev_t *dev, int bufid);
bool i2s_parallel_is_previous_buffer_free();
void link_dma_desc(volatile lldesc_t *dmadesc, volatile lldesc_t *prevdmadesc, void *memory, size_t size);
typedef void (*callback)(void);
void setShiftCompleteCallback(callback f);