qp_comms_spi.c 5.5 KB

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