qp_comms_spi.c (5655B)
1 // Copyright 2021 Nick Brassel (@tzarc) 2 // SPDX-License-Identifier: GPL-2.0-or-later 3 4 #ifdef QUANTUM_PAINTER_SPI_ENABLE 5 6 # include "spi_master.h" 7 # include "qp_comms_spi.h" 8 9 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 10 // Base SPI support 11 12 bool qp_comms_spi_init(painter_device_t device) { 13 painter_driver_t *driver = (painter_driver_t *)device; 14 qp_comms_spi_config_t *comms_config = (qp_comms_spi_config_t *)driver->comms_config; 15 16 // Initialize the SPI peripheral 17 spi_init(); 18 19 // Set up CS as output high 20 gpio_set_pin_output(comms_config->chip_select_pin); 21 gpio_write_pin_high(comms_config->chip_select_pin); 22 23 return true; 24 } 25 26 bool qp_comms_spi_start(painter_device_t device) { 27 painter_driver_t *driver = (painter_driver_t *)device; 28 qp_comms_spi_config_t *comms_config = (qp_comms_spi_config_t *)driver->comms_config; 29 30 return spi_start(comms_config->chip_select_pin, comms_config->lsb_first, comms_config->mode, comms_config->divisor); 31 } 32 33 uint32_t qp_comms_spi_send_data(painter_device_t device, const void *data, uint32_t byte_count) { 34 uint32_t bytes_remaining = byte_count; 35 const uint8_t *p = (const uint8_t *)data; 36 const uint32_t max_msg_length = 1024; 37 38 while (bytes_remaining > 0) { 39 uint32_t bytes_this_loop = MIN(bytes_remaining, max_msg_length); 40 spi_transmit(p, bytes_this_loop); 41 p += bytes_this_loop; 42 bytes_remaining -= bytes_this_loop; 43 } 44 45 return byte_count - bytes_remaining; 46 } 47 48 bool qp_comms_spi_stop(painter_device_t device) { 49 painter_driver_t *driver = (painter_driver_t *)device; 50 qp_comms_spi_config_t *comms_config = (qp_comms_spi_config_t *)driver->comms_config; 51 spi_stop(); 52 gpio_write_pin_high(comms_config->chip_select_pin); 53 return true; 54 } 55 56 const painter_comms_vtable_t spi_comms_vtable = { 57 .comms_init = qp_comms_spi_init, 58 .comms_start = qp_comms_spi_start, 59 .comms_send = qp_comms_spi_send_data, 60 .comms_stop = qp_comms_spi_stop, 61 }; 62 63 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 64 // SPI with D/C and RST pins 65 66 # ifdef QUANTUM_PAINTER_SPI_DC_RESET_ENABLE 67 68 bool qp_comms_spi_dc_reset_init(painter_device_t device) { 69 if (!qp_comms_spi_init(device)) { 70 return false; 71 } 72 73 painter_driver_t *driver = (painter_driver_t *)device; 74 qp_comms_spi_dc_reset_config_t *comms_config = (qp_comms_spi_dc_reset_config_t *)driver->comms_config; 75 76 // Set up D/C as output low, if specified 77 if (comms_config->dc_pin != NO_PIN) { 78 gpio_set_pin_output(comms_config->dc_pin); 79 gpio_write_pin_low(comms_config->dc_pin); 80 } 81 82 // Set up RST as output, if specified, performing a reset in the process 83 if (comms_config->reset_pin != NO_PIN) { 84 gpio_set_pin_output(comms_config->reset_pin); 85 gpio_write_pin_low(comms_config->reset_pin); 86 wait_ms(20); 87 gpio_write_pin_high(comms_config->reset_pin); 88 wait_ms(20); 89 } 90 91 return true; 92 } 93 94 uint32_t qp_comms_spi_dc_reset_send_data(painter_device_t device, const void *data, uint32_t byte_count) { 95 painter_driver_t *driver = (painter_driver_t *)device; 96 qp_comms_spi_dc_reset_config_t *comms_config = (qp_comms_spi_dc_reset_config_t *)driver->comms_config; 97 gpio_write_pin_high(comms_config->dc_pin); 98 return qp_comms_spi_send_data(device, data, byte_count); 99 } 100 101 bool qp_comms_spi_dc_reset_send_command(painter_device_t device, uint8_t cmd) { 102 painter_driver_t *driver = (painter_driver_t *)device; 103 qp_comms_spi_dc_reset_config_t *comms_config = (qp_comms_spi_dc_reset_config_t *)driver->comms_config; 104 gpio_write_pin_low(comms_config->dc_pin); 105 spi_write(cmd); 106 return true; 107 } 108 109 bool qp_comms_spi_dc_reset_bulk_command_sequence(painter_device_t device, const uint8_t *sequence, size_t sequence_len) { 110 painter_driver_t *driver = (painter_driver_t *)device; 111 qp_comms_spi_dc_reset_config_t *comms_config = (qp_comms_spi_dc_reset_config_t *)driver->comms_config; 112 for (size_t i = 0; i < sequence_len;) { 113 uint8_t command = sequence[i]; 114 uint8_t delay = sequence[i + 1]; 115 uint8_t num_bytes = sequence[i + 2]; 116 qp_comms_spi_dc_reset_send_command(device, command); 117 if (num_bytes > 0) { 118 if (comms_config->command_params_uses_command_pin) { 119 for (uint8_t j = 0; j < num_bytes; j++) { 120 qp_comms_spi_dc_reset_send_command(device, sequence[i + 3 + j]); 121 } 122 } else { 123 qp_comms_spi_dc_reset_send_data(device, &sequence[i + 3], num_bytes); 124 } 125 } 126 if (delay > 0) { 127 wait_ms(delay); 128 } 129 i += (3 + num_bytes); 130 } 131 132 return true; 133 } 134 135 const painter_comms_with_command_vtable_t spi_comms_with_dc_vtable = { 136 .base = 137 { 138 .comms_init = qp_comms_spi_dc_reset_init, 139 .comms_start = qp_comms_spi_start, 140 .comms_send = qp_comms_spi_dc_reset_send_data, 141 .comms_stop = qp_comms_spi_stop, 142 }, 143 .send_command = qp_comms_spi_dc_reset_send_command, 144 .bulk_command_sequence = qp_comms_spi_dc_reset_bulk_command_sequence, 145 }; 146 147 # endif // QUANTUM_PAINTER_SPI_DC_RESET_ENABLE 148 149 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 150 151 #endif // QUANTUM_PAINTER_SPI_ENABLE