PixelBone_Pixel::PixelBone_Pixel(uint16_t pixel_count) : pru0(pru_init(0)), num_pixels(pixel_count), buffer_size(pixel_count * sizeof(pixel_t)) { if (2 * buffer_size > pru0->ddr_size) die("Pixel data needs at least 2 * %zu, only %zu in DDR\n", buffer_size, pru0->ddr_size); ws281x = (ws281x_command_t *)pru0->data_ram; *(ws281x) = ws281x_command_t((unsigned)pixel_count); // Configure all of our output pins. pru_gpio(0, gpios0, 1, 0); // Initiate the PRU0 program pru_exec(pru0, "./ws281x.bin"); // Watch for a done response that indicates a proper startup // TODO: timeout if it fails std::cout << "waiting for response from pru0... "; while (!ws281x->response) ; std::cout << "OK" << std::endl; };
ledscape_t * ledscape_init_with_modes( unsigned num_pixels, ledscape_output_mode_t pru0_mode, ledscape_output_mode_t pru1_mode ) { pru_t * const pru0 = pru_init(0); pru_t * const pru1 = pru_init(1); const size_t frame_size = num_pixels * LEDSCAPE_NUM_STRIPS * 4; if (2 *frame_size > pru0->ddr_size) die("Pixel data needs at least 2 * %zu, only %zu in DDR\n", frame_size, pru0->ddr_size ); ledscape_t * const leds = calloc(1, sizeof(*leds)); *leds = (ledscape_t) { .pru0 = pru0, .pru1 = pru1, .num_pixels = num_pixels, .frame_size = frame_size, .pru0_mode = pru0_mode, .pru1_mode = pru1_mode, .ws281x_0 = pru0->data_ram, .ws281x_1 = pru1->data_ram }; *(leds->ws281x_0) = *(leds->ws281x_1) = (ws281x_command_t) { .pixels_dma = 0, // will be set in draw routine .command = 0, .response = 0, .num_pixels = leds->num_pixels, }; // Configure all of our output pins. for (unsigned i = 0 ; i < ARRAY_COUNT(gpios0) ; i++) pru_gpio(0, gpios0[i], 1, 0); for (unsigned i = 0 ; i < ARRAY_COUNT(gpios1) ; i++) pru_gpio(1, gpios1[i], 1, 0); for (unsigned i = 0 ; i < ARRAY_COUNT(gpios2) ; i++) pru_gpio(2, gpios2[i], 1, 0); for (unsigned i = 0 ; i < ARRAY_COUNT(gpios3) ; i++) pru_gpio(3, gpios3[i], 1, 0); // Initiate the PRU0 program const char* pru0_program_filename; switch (pru0_mode) { case NOP: pru0_program_filename = "./nop_0.bin"; break; case WS281x: pru0_program_filename = "./ws281x_0.bin"; break; case DMX: pru0_program_filename = "./dmx_0.bin"; break; case WS2801: pru0_program_filename = "./ws2801_0.bin"; break; case WS2801_NEWPINS: pru0_program_filename = "./ws2801_newpins_0.bin"; break; default: warn("Invalid PRU0 Mode."); pru0_program_filename = "./ws281x_0.bin"; } pru_exec(pru0, pru0_program_filename); // Watch for a done response that indicates a proper startup // \todo timeout if it fails fprintf(stdout, "String PRU0 with %s... ", pru0_program_filename); while (!leds->ws281x_0->response); printf("OK\n"); // Initiate the PRU1 program const char* pru1_program_filename; switch (pru1_mode) { case NOP: pru1_program_filename = "./nop_1.bin"; break; case WS281x: pru1_program_filename = "./ws281x_1.bin"; break; case DMX: warn("PRU1 does not currently support DMX."); pru1_program_filename = "./ws281x_1.bin"; break; case WS2801: pru1_program_filename = "./ws2801_1.bin"; break; case WS2801_NEWPINS: pru1_program_filename = "./ws2801_newpins_1.bin"; break; default: pru1_program_filename = "./ws281x_1.bin"; warn("Invalid PRU1 Mode."); } pru_exec(pru1, pru1_program_filename); // Watch for a done response that indicates a proper startup // \todo timeout if it fails fprintf(stdout, "String PRU1 with %s... ", pru1_program_filename); while (!leds->ws281x_1->response); printf("OK\n"); return leds; } void ledscape_close( ledscape_t * const leds ) { // Signal a halt command leds->ws281x_0->command = 0xFF; leds->ws281x_1->command = 0xFF; pru_close(leds->pru0); pru_close(leds->pru1); } void ledscape_set_color( ledscape_frame_t * const frame, uint8_t strip, uint16_t pixel, uint8_t r, uint8_t g, uint8_t b ) { ledscape_pixel_t * const p = &frame[pixel].strip[strip]; p->r = r; p->g = g; p->b = b; }