// Here is ESP32 code providing an ESP32 to P2 link with the ESP32 serving as the master and the P2 as the slave // Richard J. S. Morrison, July 23rd 2020 // The SPI clock here is 20 MHz allowing effective ESP32 to P2 data rates of around 2.4 MBytes/sec // My setup has the ESP32 connected to a P2-EVALB PCB; the latter having a NeoPixel 8 LED WS2812B strip connected to // one of its pins to give a visual display of activity as this code runs. // In the loop routine, various command strings are issued in sequence // Commands are of two types - : upper case and lower case // Lower case commands invoke actions just on the ESP32, while upper case commands invoke actions on the P2 // Here is a command summary (see the ESP32 code below for more information) : // bn sets the block number prior to an upload/download operation (block #'s 0-31, each block is 2k bytes) // cn fills low half (32k) of ESP32 data buffer with function data set by f command and further modified by n // d0 clears the entire 64k ESP32 data buffer // fn sets function number to n : 0 = linear, 1 = sine, 2 = cosine, 3 = sqrt // nn sets the color swatch dataset to n : (0-4) // rn fills the ESP32 data buffer with n repeating 2k blocks of color swatch data // Rn sets an RGB value of n to each LED on the WS2812 strip // Dn downloads n x 2k blocks of data from the ESP32 to the P2, using offset determined by b command // Un uploads n x 2k blocks of data from the P2 to the ESP32, using offset determined by b command // Ln fills LUT with a linear ramp with point spacing n, displays 1st 8 longs to WS2812 strip // Vn fill HUB with a ramp having slope n (set to 0 to clear hubRAM buffer) // Lengthen postcmd_delay in the setup routine (value in msec) to see each command execute in turn // A very big shout out goes to hideakitai for the esp32 dma spi library !!! - see download link below // https://www.arduino.cc/reference/en/libraries/esp32dmaspi/ // // WHY ??? // When using the standard SPI library there is a small buffer (if I recall correctly it is only 64 bytes in size) // If a large amount of data is being transferred - for example doing SPI.writeBytes((uint8_t *)send,2048) I found // that a new chip select is generated for each new buffer which is a real hassle, greatly slowing down the transfer and // considerably complicating the code on the P2. // Using the above DMA SPI library I was able to move 2048 bytes ESP32 <---> P2 LUT fairly seamlessly. // There are examples provided in the library of having the ESP32 as an SPI slave, too... // https://www.arduino.cc/reference/en/libraries/esp32dmaspi/ #include ESP32DMASPI::Master master; static const uint32_t BUFFER_SIZE = 2048; uint8_t* spi_master_tx_buf; uint8_t* spi_master_rx_buf; uint8_t command_bytes[4] ; int ledPin = 2; uint8_t dataset, fn_no, block_no ; uint16_t offset ; // Define various color swatches for our 8 LED WS2812B strip // graded greens uint32_t colors0[8]={0x00000000,0x00001000,0x00002000,0x00003000,0x00004000,0x00005000,0x00006000,0x00007000} ; // red, green, blue, orange, pink, purple, turquoise, yellow uint32_t colors1[8]={0x00FF0000,0x0000FF00,0x000000FF,0x00FF6000,0x00FF5F5F,0x008C00FF,0x003FE0C0,0x00FFFF00} ; // 4 reds, 2 greens, 2 blues uint32_t colors2[8]={0x00FF0000,0x00FF0000,0x00FF0000,0x00FF0000,0x0000FF00,0x0000FF00,0x000000FF,0x000000FF} ; // 4 whites, 4 blacks uint32_t colors3[8]={0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0x00000000,0x00000000,0x00000000,0x00000000} ; // 4 x (white, black) uint32_t colors4[8]={0xFFFFFFFF,0x00000000,0xFFFFFFFF,0x00000000,0xFFFFFFFF,0x00000000,0xFFFFFFFF,0x00000000} ; // Various command strings for testing String red = "R65536," ; String green = "R256," ; String blue = "R1," ; String white = "R65793," ; String download = "D1," ; String upload = "U1," ; String download16 = "D16," ; String upload16 = "U16," ; String ESP32block0 = "b0," ; String ESP32block16 = "b16," ; String clrESP32buf = "d0," ; String clrP2buf = "V0," ; String linear = "f0," ; String sine = "f1," ; String cosine = "f2," ; String square_root = "f3," ; String fillfun = "c2" ; String swatch0 = "n0," ; String swatch1 = "n1," ; String swatch2 = "n2," ; String swatch3 = "n3" ; String swatch4 = "n4" ; String fillcolors = "r1" ; String fillLUT = "L1048576," ; // 2^20 increment uint16_t postcmd_delay ; uint8_t databuffer[65536] ; struct P2command { uint8_t action ; uint32_t value ; uint32_t data_to_send ; }; struct P2command C; void fill_buffer() { int j, start, increment, current ; start = 0 ; increment = -256 ; current = start ; for (uint32_t i = 0; i < BUFFER_SIZE/4; i++) { j = i * 4 ; spi_master_tx_buf[j] = (current >> 24) & 0xFF ; spi_master_tx_buf[j+1] = (current >> 16) & 0xFF ; spi_master_tx_buf[j+2] = (current >> 8) & 0xFF ; spi_master_tx_buf[j+3] = current & 0xFF ; current = current + increment ; } memset(spi_master_rx_buf, 0, BUFFER_SIZE); } // fills databuffer with n repeating 2k blocks of color swatch data void ESP32_fill_memory(uint32_t n) { uint16_t i, j ; uint32_t k ; for(i=0; i<(512*n); i++) { j = i * 4 ; k = i % 8 ; switch(dataset) { case 0: databuffer[j] = colors0[k] >> 24 ; databuffer[j+1] = (colors0[k] >> 16) & 0xff ; databuffer[j+2] = (colors0[k] >> 8) & 0xff ; databuffer[j+3] = colors0[k] & 0xff ; break ; case 1: databuffer[j] = colors1[k] >> 24 ; databuffer[j+1] = (colors1[k] >> 16) & 0xff ; databuffer[j+2] = (colors1[k] >> 8) & 0xff ; databuffer[j+3] = colors1[k] & 0xff ; break ; case 2: databuffer[j] = colors2[k] >> 24 ; databuffer[j+1] = (colors2[k] >> 16) & 0xff ; databuffer[j+2] = (colors2[k] >> 8) & 0xff ; databuffer[j+3] = colors2[k] & 0xff ; break ; case 3: databuffer[j] = colors3[k] >> 24 ; databuffer[j+1] = (colors3[k] >> 16) & 0xff ; databuffer[j+2] = (colors3[k] >> 8) & 0xff ; databuffer[j+3] = colors3[k] & 0xff ; break ; case 4: databuffer[j] = colors4[k] >> 24 ; databuffer[j+1] = (colors4[k] >> 16) & 0xff ; databuffer[j+2] = (colors4[k] >> 8) & 0xff ; databuffer[j+3] = colors4[k] & 0xff ; break ; } } } // Decodes an input string (comma terminated) into a structure // returns a 4 byte long for transmission to the P2-EVAL from // a users string command that is comma terminated // reminder - first character in a string has address 0 void do_command(String s) { uint8_t pos ; uint32_t i, j, k, result ; String t ; C.action = s[0] ; pos = s.indexOf(',') ; t = s.substring(1,pos) ; C.value = t.toInt() ; C.data_to_send = (C.action << 24) + C.value ; command_bytes[0] = C.action ; command_bytes[1] = C.value >> 16 ; command_bytes[2] = (C.value >> 8) & 0xFF ; command_bytes[3] = C.value & 0xFF ; if(isLowerCase(C.action)) // its a local command { switch(C.action) { case 'n': // color swatch dataset (0-3) dataset = C.value ; break ; case 'c': // fills low half of data buffer with function data # modified by C.value digitalWrite(ledPin, HIGH); for(i=0; i<32768; i++) { switch(fn_no) { case 0: databuffer[i] = C.value * (i/512) ; break ; case 1: databuffer[i] = 127 + 127 * sin((float (i)/(32768.0/C.value))*6.2832) ; break ; case 2: databuffer[i] = 127 + 127 * cos((float (i)/(32768.0/C.value))*6.2832) ; break ; case 3: databuffer[i] = sqrt(i*C.value) ; break ; } } digitalWrite(ledPin, LOW); break ; case 'b': // sets starting block # for data downloads/uploads - ESP32 buffer is 32 x 2k blocks numbered 0 to 31 block_no = C.value ; offset = block_no * 2048 ; // offset into ESP32 data buffer - this will be used when downloading/uploading break ; case 'd': // clears entire data buffer for(i=0; i<65536; i++) databuffer[i] = 0 ; break ; case 'f': // sets function number : 0 = linear, 1 = sine, 2 = cosine, 3 = sqrt fn_no = C.value ; break ; case 'r': ESP32_fill_memory(C.value); break ; } } else // its a command requiring action on the P2; various delays in here ensure P2 action has completed !! { // send command to P2 master.transfer(command_bytes, spi_master_rx_buf, 4); // send a command to P2EVALB switch(C.action) { case 'R': // display one RGB value on WS2812 break ; case 'V': // clearing HUBRAM takes 610 usec; allow time for completion delayMicroseconds(2000) ; break ; case 'L': // filling LUT and displaying 8 longs to WS2812 takes 520 usec; allow time for completion delayMicroseconds(2000) ; break ; case 'D': // data download from ESP32 to P2 - P56 LED flashes for(i=0; i