138 lines
5.1 KiB
C
138 lines
5.1 KiB
C
|
// Copyright 2021 Nick Brassel (@tzarc)
|
||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||
|
|
||
|
#ifdef QUANTUM_PAINTER_SPI_ENABLE
|
||
|
|
||
|
# include "spi_master.h"
|
||
|
# include "qp_comms_spi.h"
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
// Base SPI support
|
||
|
|
||
|
bool qp_comms_spi_init(painter_device_t device) {
|
||
|
struct painter_driver_t * driver = (struct painter_driver_t *)device;
|
||
|
struct qp_comms_spi_config_t *comms_config = (struct qp_comms_spi_config_t *)driver->comms_config;
|
||
|
|
||
|
// Initialize the SPI peripheral
|
||
|
spi_init();
|
||
|
|
||
|
// Set up CS as output high
|
||
|
setPinOutput(comms_config->chip_select_pin);
|
||
|
writePinHigh(comms_config->chip_select_pin);
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool qp_comms_spi_start(painter_device_t device) {
|
||
|
struct painter_driver_t * driver = (struct painter_driver_t *)device;
|
||
|
struct qp_comms_spi_config_t *comms_config = (struct qp_comms_spi_config_t *)driver->comms_config;
|
||
|
|
||
|
return spi_start(comms_config->chip_select_pin, comms_config->lsb_first, comms_config->mode, comms_config->divisor);
|
||
|
}
|
||
|
|
||
|
uint32_t qp_comms_spi_send_data(painter_device_t device, const void *data, uint32_t byte_count) {
|
||
|
uint32_t bytes_remaining = byte_count;
|
||
|
const uint8_t *p = (const uint8_t *)data;
|
||
|
while (bytes_remaining > 0) {
|
||
|
uint32_t bytes_this_loop = bytes_remaining < 1024 ? bytes_remaining : 1024;
|
||
|
spi_transmit(p, bytes_this_loop);
|
||
|
p += bytes_this_loop;
|
||
|
bytes_remaining -= bytes_this_loop;
|
||
|
}
|
||
|
|
||
|
return byte_count - bytes_remaining;
|
||
|
}
|
||
|
|
||
|
void qp_comms_spi_stop(painter_device_t device) {
|
||
|
struct painter_driver_t * driver = (struct painter_driver_t *)device;
|
||
|
struct qp_comms_spi_config_t *comms_config = (struct qp_comms_spi_config_t *)driver->comms_config;
|
||
|
spi_stop();
|
||
|
writePinHigh(comms_config->chip_select_pin);
|
||
|
}
|
||
|
|
||
|
const struct painter_comms_vtable_t spi_comms_vtable = {
|
||
|
.comms_init = qp_comms_spi_init,
|
||
|
.comms_start = qp_comms_spi_start,
|
||
|
.comms_send = qp_comms_spi_send_data,
|
||
|
.comms_stop = qp_comms_spi_stop,
|
||
|
};
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
// SPI with D/C and RST pins
|
||
|
|
||
|
# ifdef QUANTUM_PAINTER_SPI_DC_RESET_ENABLE
|
||
|
|
||
|
bool qp_comms_spi_dc_reset_init(painter_device_t device) {
|
||
|
if (!qp_comms_spi_init(device)) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
struct painter_driver_t * driver = (struct painter_driver_t *)device;
|
||
|
struct qp_comms_spi_dc_reset_config_t *comms_config = (struct qp_comms_spi_dc_reset_config_t *)driver->comms_config;
|
||
|
|
||
|
// Set up D/C as output low, if specified
|
||
|
if (comms_config->dc_pin != NO_PIN) {
|
||
|
setPinOutput(comms_config->dc_pin);
|
||
|
writePinLow(comms_config->dc_pin);
|
||
|
}
|
||
|
|
||
|
// Set up RST as output, if specified, performing a reset in the process
|
||
|
if (comms_config->reset_pin != NO_PIN) {
|
||
|
setPinOutput(comms_config->reset_pin);
|
||
|
writePinLow(comms_config->reset_pin);
|
||
|
wait_ms(20);
|
||
|
writePinHigh(comms_config->reset_pin);
|
||
|
wait_ms(20);
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
uint32_t qp_comms_spi_dc_reset_send_data(painter_device_t device, const void *data, uint32_t byte_count) {
|
||
|
struct painter_driver_t * driver = (struct painter_driver_t *)device;
|
||
|
struct qp_comms_spi_dc_reset_config_t *comms_config = (struct qp_comms_spi_dc_reset_config_t *)driver->comms_config;
|
||
|
writePinHigh(comms_config->dc_pin);
|
||
|
return qp_comms_spi_send_data(device, data, byte_count);
|
||
|
}
|
||
|
|
||
|
void qp_comms_spi_dc_reset_send_command(painter_device_t device, uint8_t cmd) {
|
||
|
struct painter_driver_t * driver = (struct painter_driver_t *)device;
|
||
|
struct qp_comms_spi_dc_reset_config_t *comms_config = (struct qp_comms_spi_dc_reset_config_t *)driver->comms_config;
|
||
|
writePinLow(comms_config->dc_pin);
|
||
|
spi_write(cmd);
|
||
|
}
|
||
|
|
||
|
void qp_comms_spi_dc_reset_bulk_command_sequence(painter_device_t device, const uint8_t *sequence, size_t sequence_len) {
|
||
|
for (size_t i = 0; i < sequence_len;) {
|
||
|
uint8_t command = sequence[i];
|
||
|
uint8_t delay = sequence[i + 1];
|
||
|
uint8_t num_bytes = sequence[i + 2];
|
||
|
qp_comms_spi_dc_reset_send_command(device, command);
|
||
|
if (num_bytes > 0) {
|
||
|
qp_comms_spi_dc_reset_send_data(device, &sequence[i + 3], num_bytes);
|
||
|
}
|
||
|
if (delay > 0) {
|
||
|
wait_ms(delay);
|
||
|
}
|
||
|
i += (3 + num_bytes);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
const struct painter_comms_with_command_vtable_t spi_comms_with_dc_vtable = {
|
||
|
.base =
|
||
|
{
|
||
|
.comms_init = qp_comms_spi_dc_reset_init,
|
||
|
.comms_start = qp_comms_spi_start,
|
||
|
.comms_send = qp_comms_spi_dc_reset_send_data,
|
||
|
.comms_stop = qp_comms_spi_stop,
|
||
|
},
|
||
|
.send_command = qp_comms_spi_dc_reset_send_command,
|
||
|
.bulk_command_sequence = qp_comms_spi_dc_reset_bulk_command_sequence,
|
||
|
};
|
||
|
|
||
|
# endif // QUANTUM_PAINTER_SPI_DC_RESET_ENABLE
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
#endif // QUANTUM_PAINTER_SPI_ENABLE
|