2018-10-23 02:00:47 +02:00
# include "ESP32-RGB64x32MatrixPanel-I2S-DMA.h"
// Credits: Louis Beaudoin <https://github.com/pixelmatix/SmartMatrix/tree/teensylc>
// and Sprite_TM: https://www.esp32.com/viewtopic.php?f=17&t=3188 and https://www.esp32.com/viewtopic.php?f=13&t=3256
Added ability to define custom pin mappings
Closes issue #4
Use something like:
' display.begin(R1_PIN, G1_PIN, B1_PIN, R2_PIN, G2_PIN, B2_PIN, A_PIN, B_PIN, C_PIN, D_PIN, E_PIN, LAT_PIN, OE_PIN, CLK_PIN ); // setup the LED matrix'
with R1_PIN etc. referring to your own define or constant variables
2019-01-03 01:22:48 +01:00
void RGB64x32MatrixPanel_I2S_DMA : : configureDMA ( int r1_pin , int g1_pin , int b1_pin , int r2_pin , int g2_pin , int b2_pin , int a_pin , int b_pin , int c_pin , int d_pin , int e_pin , int lat_pin , int oe_pin , int clk_pin )
2018-10-23 02:00:47 +02:00
{
// calculate the lowest LSBMSB_TRANSITION_BIT value that will fit in memory
int numDescriptorsPerRow ;
lsbMsbTransitionBit = 0 ;
while ( 1 ) {
numDescriptorsPerRow = 1 ;
for ( int i = lsbMsbTransitionBit + 1 ; i < COLOR_DEPTH_BITS ; i + + ) {
numDescriptorsPerRow + = 1 < < ( i - lsbMsbTransitionBit - 1 ) ;
}
int ramrequired = numDescriptorsPerRow * ROWS_PER_FRAME * ESP32_NUM_FRAME_BUFFERS * sizeof ( lldesc_t ) ;
2019-01-04 00:09:00 +01:00
ramrequired + = 64000 ; // HACK Hard Coded: Keep at least 64k free!
2018-10-23 02:00:47 +02:00
int largestblockfree = heap_caps_get_largest_free_block ( MALLOC_CAP_DMA ) ;
Serial . printf ( " lsbMsbTransitionBit of %d requires %d RAM, %d available, leaving %d free: \r \n " , lsbMsbTransitionBit , ramrequired , largestblockfree , largestblockfree - ramrequired ) ;
if ( ramrequired < ( largestblockfree ) )
break ;
if ( lsbMsbTransitionBit < COLOR_DEPTH_BITS - 1 )
lsbMsbTransitionBit + + ;
else
break ;
}
if ( numDescriptorsPerRow * ROWS_PER_FRAME * ESP32_NUM_FRAME_BUFFERS * sizeof ( lldesc_t ) > heap_caps_get_largest_free_block ( MALLOC_CAP_DMA ) ) {
assert ( " Not enough RAM for SmartMatrix descriptors " ) ;
Serial . printf ( " Not enough RAM for SmartMatrix descriptors \r \n " ) ;
return ;
}
Serial . printf ( " Raised lsbMsbTransitionBit to %d/%d to fit in RAM \r \n " , lsbMsbTransitionBit , COLOR_DEPTH_BITS - 1 ) ;
// calculate the lowest LSBMSB_TRANSITION_BIT value that will fit in memory that will meet or exceed the configured refresh rate
while ( 1 ) {
int psPerClock = 1000000000000UL / ESP32_I2S_CLOCK_SPEED ;
int nsPerLatch = ( ( PIXELS_PER_LATCH + CLKS_DURING_LATCH ) * psPerClock ) / 1000 ;
Serial . printf ( " ns per latch: %d: \r \n " , nsPerLatch ) ;
// add time to shift out LSBs + LSB-MSB transition bit - this ignores fractions...
int nsPerRow = COLOR_DEPTH_BITS * nsPerLatch ;
// add time to shift out MSBs
for ( int i = lsbMsbTransitionBit + 1 ; i < COLOR_DEPTH_BITS ; i + + )
nsPerRow + = ( 1 < < ( i - lsbMsbTransitionBit - 1 ) ) * ( COLOR_DEPTH_BITS - i ) * nsPerLatch ;
//Serial.printf("nsPerRow: %d: \r\n", nsPerRow);
int nsPerFrame = nsPerRow * ROWS_PER_FRAME ;
Serial . printf ( " nsPerFrame: %d: \r \n " , nsPerFrame ) ;
int actualRefreshRate = 1000000000UL / ( nsPerFrame ) ;
refreshRate = actualRefreshRate ;
Serial . printf ( " lsbMsbTransitionBit of %d gives %d Hz refresh: \r \n " , lsbMsbTransitionBit , actualRefreshRate ) ;
2019-07-29 14:45:06 +02:00
if ( actualRefreshRate > min_refresh_rate ) // HACK Hard Coded: 100
2018-10-23 02:00:47 +02:00
break ;
if ( lsbMsbTransitionBit < COLOR_DEPTH_BITS - 1 )
lsbMsbTransitionBit + + ;
else
break ;
}
Serial . printf ( " Raised lsbMsbTransitionBit to %d/%d to meet minimum refresh rate \r \n " , lsbMsbTransitionBit , COLOR_DEPTH_BITS - 1 ) ;
// TODO: completely fill buffer with data before enabling DMA - can't do this now, lsbMsbTransition bit isn't set in the calc class - also this call will probably have no effect as matrixCalcDivider will skip the first call
//matrixCalcCallback();
// lsbMsbTransition Bit is now finalized - redo descriptor count in case it changed to hit min refresh rate
numDescriptorsPerRow = 1 ;
for ( int i = lsbMsbTransitionBit + 1 ; i < COLOR_DEPTH_BITS ; i + + ) {
numDescriptorsPerRow + = 1 < < ( i - lsbMsbTransitionBit - 1 ) ;
}
Serial . printf ( " Descriptors for lsbMsbTransitionBit %d/%d with %d rows require %d bytes of DMA RAM \r \n " , lsbMsbTransitionBit , COLOR_DEPTH_BITS - 1 , ROWS_PER_FRAME , 2 * numDescriptorsPerRow * ROWS_PER_FRAME * sizeof ( lldesc_t ) ) ;
// malloc the DMA linked list descriptors that i2s_parallel will need
int desccount = numDescriptorsPerRow * ROWS_PER_FRAME ;
lldesc_t * dmadesc_a = ( lldesc_t * ) heap_caps_malloc ( desccount * sizeof ( lldesc_t ) , MALLOC_CAP_DMA ) ;
assert ( " Can't allocate descriptor buffer a " ) ;
if ( ! dmadesc_a ) {
Serial . printf ( " Could not malloc descriptor buffer a. " ) ;
return ;
}
lldesc_t * dmadesc_b = ( lldesc_t * ) heap_caps_malloc ( desccount * sizeof ( lldesc_t ) , MALLOC_CAP_DMA ) ;
assert ( " Could not malloc descriptor buffer b. " ) ;
if ( ! dmadesc_b ) {
Serial . printf ( " can't malloc " ) ;
return ;
}
Serial . printf ( " SmartMatrix Mallocs Complete \r \n " ) ;
Serial . printf ( " Heap Memory Available: %d bytes total, %d bytes largest free block: \r \n " , heap_caps_get_free_size ( 0 ) , heap_caps_get_largest_free_block ( 0 ) ) ;
Serial . printf ( " 8-bit Accessible Memory Available: %d bytes total, %d bytes largest free block: \r \n " , heap_caps_get_free_size ( MALLOC_CAP_8BIT ) , heap_caps_get_largest_free_block ( MALLOC_CAP_8BIT ) ) ;
Serial . printf ( " 32-bit Memory Available: %d bytes total, %d bytes largest free block: \r \n " , heap_caps_get_free_size ( MALLOC_CAP_32BIT ) , heap_caps_get_largest_free_block ( MALLOC_CAP_32BIT ) ) ;
Serial . printf ( " DMA Memory Available: %d bytes total, %d bytes largest free block: \r \n " , heap_caps_get_free_size ( MALLOC_CAP_DMA ) , heap_caps_get_largest_free_block ( MALLOC_CAP_DMA ) ) ;
lldesc_t * prevdmadesca = 0 ;
lldesc_t * prevdmadescb = 0 ;
int currentDescOffset = 0 ;
// fill DMA linked lists for both frames
for ( int j = 0 ; j < ROWS_PER_FRAME ; j + + ) {
// first set of data is LSB through MSB, single pass - all color bits are displayed once, which takes care of everything below and inlcluding LSBMSB_TRANSITION_BIT
// TODO: size must be less than DMA_MAX - worst case for SmartMatrix Library: 16-bpp with 256 pixels per row would exceed this, need to break into two
link_dma_desc ( & dmadesc_a [ currentDescOffset ] , prevdmadesca , & ( matrixUpdateFrames [ 0 ] . rowdata [ j ] . rowbits [ 0 ] . data ) , sizeof ( rowBitStruct ) * COLOR_DEPTH_BITS ) ;
prevdmadesca = & dmadesc_a [ currentDescOffset ] ;
link_dma_desc ( & dmadesc_b [ currentDescOffset ] , prevdmadescb , & ( matrixUpdateFrames [ 1 ] . rowdata [ j ] . rowbits [ 0 ] . data ) , sizeof ( rowBitStruct ) * COLOR_DEPTH_BITS ) ;
prevdmadescb = & dmadesc_b [ currentDescOffset ] ;
currentDescOffset + + ;
//Serial.printf("row %d: \r\n", j);
for ( int i = lsbMsbTransitionBit + 1 ; i < COLOR_DEPTH_BITS ; i + + ) {
// binary time division setup: we need 2 of bit (LSBMSB_TRANSITION_BIT + 1) four of (LSBMSB_TRANSITION_BIT + 2), etc
// because we sweep through to MSB each time, it divides the number of times we have to sweep in half (saving linked list RAM)
// we need 2^(i - LSBMSB_TRANSITION_BIT - 1) == 1 << (i - LSBMSB_TRANSITION_BIT - 1) passes from i to MSB
//Serial.printf("buffer %d: repeat %d times, size: %d, from %d - %d\r\n", nextBufdescIndex, 1<<(i - LSBMSB_TRANSITION_BIT - 1), (COLOR_DEPTH_BITS - i), i, COLOR_DEPTH_BITS-1);
for ( int k = 0 ; k < 1 < < ( i - lsbMsbTransitionBit - 1 ) ; k + + ) {
link_dma_desc ( & dmadesc_a [ currentDescOffset ] , prevdmadesca , & ( matrixUpdateFrames [ 0 ] . rowdata [ j ] . rowbits [ i ] . data ) , sizeof ( rowBitStruct ) * ( COLOR_DEPTH_BITS - i ) ) ;
prevdmadesca = & dmadesc_a [ currentDescOffset ] ;
link_dma_desc ( & dmadesc_b [ currentDescOffset ] , prevdmadescb , & ( matrixUpdateFrames [ 1 ] . rowdata [ j ] . rowbits [ i ] . data ) , sizeof ( rowBitStruct ) * ( COLOR_DEPTH_BITS - i ) ) ;
prevdmadescb = & dmadesc_b [ currentDescOffset ] ;
currentDescOffset + + ;
//Serial.printf("i %d, j %d, k %d\r\n", i, j, k);
}
}
}
//End markers
dmadesc_a [ desccount - 1 ] . eof = 1 ;
dmadesc_b [ desccount - 1 ] . eof = 1 ;
dmadesc_a [ desccount - 1 ] . qe . stqe_next = ( lldesc_t * ) & dmadesc_a [ 0 ] ;
dmadesc_b [ desccount - 1 ] . qe . stqe_next = ( lldesc_t * ) & dmadesc_b [ 0 ] ;
Serial . printf ( " Performing I2S setup. \n " ) ;
Added ability to define custom pin mappings
Closes issue #4
Use something like:
' display.begin(R1_PIN, G1_PIN, B1_PIN, R2_PIN, G2_PIN, B2_PIN, A_PIN, B_PIN, C_PIN, D_PIN, E_PIN, LAT_PIN, OE_PIN, CLK_PIN ); // setup the LED matrix'
with R1_PIN etc. referring to your own define or constant variables
2019-01-03 01:22:48 +01:00
i2s_parallel_config_t cfg = {
. gpio_bus = { r1_pin , g1_pin , b1_pin , r2_pin , g2_pin , b2_pin , lat_pin , oe_pin , a_pin , b_pin , c_pin , d_pin , e_pin , - 1 , - 1 , - 1 } ,
. gpio_clk = clk_pin ,
2018-10-23 02:00:47 +02:00
. clkspeed_hz = ESP32_I2S_CLOCK_SPEED , //ESP32_I2S_CLOCK_SPEED, // formula used is 80000000L/(cfg->clkspeed_hz + 1), must result in >=2. Acceptable values 26.67MHz, 20MHz, 16MHz, 13.34MHz...
. bits = MATRIX_I2S_MODE , //MATRIX_I2S_MODE,
. bufa = 0 ,
. bufb = 0 ,
desccount ,
desccount ,
dmadesc_a ,
dmadesc_b
} ;
//Setup I2S
i2s_parallel_setup_without_malloc ( & I2S1 , & cfg ) ;
Serial . printf ( " I2S setup done. \n " ) ;
// Just os we know
dma_configuration_success = true ;
} // end initMatrixDMABuff
2019-01-03 00:09:32 +01:00
/* Update a specific co-ordinate in the DMA buffer */
2018-10-23 02:00:47 +02:00
void RGB64x32MatrixPanel_I2S_DMA : : updateMatrixDMABuffer ( int16_t x_coord , int16_t y_coord , uint8_t red , uint8_t green , uint8_t blue )
{
if ( ! dma_configuration_success )
assert ( " DMA configuration in begin() not performed or completed successfully. " ) ;
2018-10-29 23:48:57 +01:00
// Need to check that the co-ordinates are within range, or it'll break everything big time.
if ( x_coord < 0 | | y_coord < 0 | | x_coord > = MATRIX_WIDTH | | y_coord > = MATRIX_HEIGHT )
2018-10-23 02:00:47 +02:00
{
2019-05-11 16:20:53 +02:00
// Serial.printf("Invalid: x %d, y %d - r %d, g %d, b %d\n", (int)x_coord, (int)y_coord, (int)red, (int)green, (int)blue );
// x_coord = y_coord = 1;
return ;
2018-10-23 02:00:47 +02:00
}
2019-01-12 18:20:49 +01:00
// What half of the HUB75 panel are we painting to?
2018-10-23 02:00:47 +02:00
bool paint_top_half = true ;
if ( y_coord > ROWS_PER_FRAME - 1 ) // co-ords start at zero, y_coord = 15 = 16 (rows per frame)
{
y_coord - = ROWS_PER_FRAME ; // if it's 16, subtract 16. Array position 0 again.
paint_top_half = false ;
}
for ( int color_depth_idx = 0 ; color_depth_idx < COLOR_DEPTH_BITS ; color_depth_idx + + ) // color depth - 8 iterations
{
uint16_t mask = ( 1 < < color_depth_idx ) ; // 24 bit color
// The destination for the pixel bitstream
rowBitStruct * p = & matrixUpdateFrames [ backbuf_id ] . rowdata [ y_coord ] . rowbits [ color_depth_idx ] ; //matrixUpdateFrames location to write to uint16_t's
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 = y_coord ;
// 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 = y_coord - 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
2019-07-29 12:00:04 +02:00
/* ORIG
2018-10-23 02:00:47 +02:00
// 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 ;
2019-07-29 12:00:04 +02:00
// 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 ;
// 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 - 2 ) v | = BIT_OE ;
2018-10-23 02:00:47 +02:00
// 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
2018-10-30 00:29:42 +01:00
if ( ( color_depth_idx > lsbMsbTransitionBit | | ! color_depth_idx ) & & ( ( x_coord ) > = brightness ) ) v | = BIT_OE ; // For Brightness
2018-10-23 02:00:47 +02:00
// 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 ) ;
2018-10-30 00:29:42 +01:00
if ( ( x_coord ) > = lsbBrightness ) v | = BIT_OE ; // For Brightness
2018-10-23 02:00:47 +02:00
}
2019-01-04 00:09:00 +01:00
/* When using the Adafruit drawPixel, we only have one pixel co-ordinate and colour to draw (duh)
2018-10-23 02:00:47 +02:00
* 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 )
2019-01-04 00:09:00 +01:00
* and persist this when we refresh .
2018-10-23 02:00:47 +02:00
*
2019-01-12 18:20:49 +01:00
* The DMA buffer order has also been reversed ( refer to the last code in this function )
2019-01-04 00:09:00 +01:00
* so we have to check for this and check the correct position of the MATRIX_DATA_STORAGE_TYPE
2018-10-23 02:00:47 +02:00
* data .
*/
int16_t tmp_x_coord = x_coord ;
if ( x_coord % 2 )
{
tmp_x_coord - = 1 ;
} else {
tmp_x_coord + = 1 ;
} // end reordering
if ( paint_top_half )
{ // 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 ;
// Persist what was painted to the other half of the frame equiv. pixel
if ( p - > data [ tmp_x_coord ] & BIT_R2 )
v | = BIT_R2 ;
if ( p - > data [ tmp_x_coord ] & BIT_G2 )
v | = BIT_G2 ;
if ( p - > data [ tmp_x_coord ] & BIT_B2 )
v | = BIT_B2 ;
}
else
{ // 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 ;
// Copy
if ( p - > data [ tmp_x_coord ] & BIT_R1 )
v | = BIT_R1 ;
if ( p - > data [ tmp_x_coord ] & BIT_G1 )
v | = BIT_G1 ;
if ( p - > data [ tmp_x_coord ] & BIT_B1 )
v | = BIT_B1 ;
} // paint
2019-07-29 12:00:04 +02:00
//Serial.printf("x: %d, y: %d ", x_coord, y_coord );
//Serial.println(v, BIN);
2018-10-23 02:00:47 +02:00
// 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
} // color depth loop (8)
2019-01-10 00:51:27 +01:00
2019-01-12 18:20:49 +01:00
//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()
2019-01-10 00:51:27 +01:00
2018-10-23 02:00:47 +02:00
} // updateDMABuffer
2019-01-03 00:09:32 +01:00
/* Update the entire buffer with a single specific colour - quicker */
void RGB64x32MatrixPanel_I2S_DMA : : updateMatrixDMABuffer ( uint8_t red , uint8_t green , uint8_t blue )
{
for ( unsigned int y_coord = 0 ; y_coord < ROWS_PER_FRAME ; y_coord + + ) // half height - 16 iterations
{
for ( int color_depth_idx = 0 ; color_depth_idx < COLOR_DEPTH_BITS ; color_depth_idx + + ) // color depth - 8 iterations
{
uint16_t mask = ( 1 < < color_depth_idx ) ; // 24 bit color
// The destination for the pixel bitstream
rowBitStruct * p = & matrixUpdateFrames [ backbuf_id ] . rowdata [ y_coord ] . rowbits [ color_depth_idx ] ; //matrixUpdateFrames location to write to uint16_t's
for ( int x_coord = 0 ; x_coord < MATRIX_WIDTH ; x_coord + + ) // row pixel width 64 iterations
{
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 = y_coord ;
// 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 = y_coord - 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
2019-07-29 12:00:04 +02:00
/* ORIG
2019-01-03 00:09:32 +01:00
// 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 ;
2019-07-29 12:00:04 +02:00
// 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 ;
// 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 - 2 ) v | = BIT_OE ;
2019-01-03 00:09:32 +01:00
// 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
}
// Top half colours
if ( green & mask )
v | = BIT_G1 ;
if ( blue & mask )
v | = BIT_B1 ;
if ( red & mask )
v | = BIT_R1 ;
// 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
} // colour depth loop (8)
} // end row iteration
2019-01-12 18:20:49 +01:00
2019-01-10 00:51:27 +01:00
2019-01-03 00:09:32 +01:00
//Show our work!
2019-01-10 00:51:27 +01:00
//i2s_parallel_flip_to_buffer(&I2S1, backbuf_id);
2019-01-12 18:20:49 +01:00
// 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()
2019-01-03 00:09:32 +01:00
} // updateDMABuffer