nodemcu-firmware/components/platform/ucg_nodemcu_hal.c

216 lines
6.1 KiB
C
Raw Normal View History

2018-10-04 23:01:34 +02:00
#include <string.h>
#include "driver/gpio.h"
#include "driver/spi_master.h"
#include "platform.h"
#include "ucg_nodemcu_hal.h"
// static variables containing info about the spi link
// TODO: move to user space once available
typedef struct {
uint8_t host;
spi_device_handle_t device;
uint8_t last_dc;
} hal_spi_t;
// transfers with payload smaller than this should be done in
// polling mode to save overhead
#define SPI_TRANSFER_POLLING_TRESHOLD 16
static void send_byte( hal_spi_t *hal, uint8_t data ) {
spi_transaction_t trans;
memset( &trans, 0, sizeof( trans ) );
trans.flags = SPI_TRANS_USE_TXDATA;
trans.length = 8;
trans.tx_data[0] = data;
spi_device_polling_transmit( hal->device, &trans );
}
// send buffer in DMA'able RAM for caching data in bigger transfers
#define SEND_BUFFER_SIZE (2*3 * 20)
static DMA_ATTR uint8_t send_buffer[SEND_BUFFER_SIZE];
int16_t ucg_com_nodemcu_hw_spi(ucg_t *ucg, int16_t msg, uint16_t arg, uint8_t *data)
{
hal_spi_t *hal = ((ucg_nodemcu_t *)ucg)->hal;
switch(msg) {
case UCG_COM_MSG_POWER_UP:
/* "data" is a pointer to ucg_com_info_t structure with the following information: */
/* ((ucg_com_info_t *)data)->serial_clk_speed value in nanoseconds */
/* ((ucg_com_info_t *)data)->parallel_clk_speed value in nanoseconds */
/* setup pins */
for (int idx = 0; idx < UCG_PIN_COUNT; idx++) {
if (ucg->pin_list[idx] != UCG_PIN_VAL_NONE) {
// configure pin as output
gpio_config_t cfg;
memset( (void *)&cfg, 0, sizeof( cfg ) );
cfg.pin_bit_mask = 1ULL << ucg->pin_list[idx];
cfg.mode = GPIO_MODE_OUTPUT;
cfg.pull_up_en = GPIO_PULLUP_DISABLE;
cfg.pull_down_en = GPIO_PULLDOWN_DISABLE;
cfg.intr_type = GPIO_INTR_DISABLE;
gpio_config( &cfg );
}
}
{
// the hal member initially contains the spi host id
int host = (int)hal;
if (!(hal = malloc( sizeof ( hal_spi_t ) )))
return 0;
hal->host = host;
((ucg_nodemcu_t *)ucg)->hal = hal;
// set up the spi device
spi_device_interface_config_t config;
memset( &config, 0, sizeof( config ) );
config.spics_io_num = -1; // CS is controlled by ucg gpio mechanism
config.mode = 0;
config.clock_speed_hz = 10000000;
config.queue_size = 1;
spi_bus_add_device( hal->host, &config, &(hal->device) );
hal->last_dc = 0;
}
break;
case UCG_COM_MSG_POWER_DOWN:
break;
case UCG_COM_MSG_DELAY:
ets_delay_us(arg);
break;
case UCG_COM_MSG_CHANGE_RESET_LINE:
if (ucg->pin_list[UCG_PIN_RST] != UCG_PIN_VAL_NONE)
gpio_set_level( ucg->pin_list[UCG_PIN_RST], arg );
break;
case UCG_COM_MSG_CHANGE_CS_LINE:
if ( ucg->pin_list[UCG_PIN_CS] != UCG_PIN_VAL_NONE )
gpio_set_level( ucg->pin_list[UCG_PIN_CS], arg );
break;
case UCG_COM_MSG_CHANGE_CD_LINE:
gpio_set_level( ucg->pin_list[UCG_PIN_CD], arg );
break;
case UCG_COM_MSG_SEND_BYTE:
send_byte( hal, arg );
break;
case UCG_COM_MSG_REPEAT_1_BYTE:
{
spi_transaction_t trans;
memset( &trans, 0, sizeof( trans ) );
trans.tx_buffer = send_buffer;
while (arg > 0) {
size_t idx;
for (idx = 0; (idx < SEND_BUFFER_SIZE) && (arg > 0); idx++, arg--) {
send_buffer[idx] = data[0];
}
trans.length = idx * 8;
trans.rxlength = 0;
if (idx < SPI_TRANSFER_POLLING_TRESHOLD) {
spi_device_polling_transmit( hal->device, &trans );
} else {
spi_device_transmit( hal->device, &trans );
}
}
}
break;
case UCG_COM_MSG_REPEAT_2_BYTES:
{
spi_transaction_t trans;
memset( &trans, 0, sizeof( trans ) );
trans.tx_buffer = send_buffer;
while (arg > 0) {
size_t idx;
for (idx = 0; (idx < SEND_BUFFER_SIZE) && (arg > 0); idx += 2, arg--) {
send_buffer[idx] = data[0];
send_buffer[idx+1] = data[1];
}
trans.length = idx * 8;
trans.rxlength = 0;
if (idx < SPI_TRANSFER_POLLING_TRESHOLD) {
spi_device_polling_transmit( hal->device, &trans );
} else {
spi_device_transmit( hal->device, &trans );
}
}
}
break;
case UCG_COM_MSG_REPEAT_3_BYTES:
{
spi_transaction_t trans;
memset( &trans, 0, sizeof( trans ) );
trans.tx_buffer = send_buffer;
while (arg > 0) {
size_t idx;
for (idx = 0; (idx < SEND_BUFFER_SIZE) && (arg > 0); idx += 3, arg--) {
send_buffer[idx] = data[0];
send_buffer[idx+1] = data[1];
send_buffer[idx+2] = data[2];
}
trans.length = idx * 8;
trans.rxlength = 0;
if (idx < SPI_TRANSFER_POLLING_TRESHOLD) {
spi_device_polling_transmit( hal->device, &trans );
} else {
spi_device_transmit( hal->device, &trans );
}
}
}
break;
case UCG_COM_MSG_SEND_STR:
{
spi_transaction_t trans;
memset( &trans, 0, sizeof( trans ) );
trans.tx_buffer = send_buffer;
while (arg > 0) {
size_t len = arg > SEND_BUFFER_SIZE ? SEND_BUFFER_SIZE : arg;
trans.length = len * 8;
trans.rxlength = 0;
memcpy( send_buffer, data, len );
if (len < SPI_TRANSFER_POLLING_TRESHOLD) {
spi_device_polling_transmit( hal->device, &trans );
} else {
spi_device_transmit( hal->device, &trans );
}
arg -= len;
}
}
break;
case UCG_COM_MSG_SEND_CD_DATA_SEQUENCE:
while (arg > 0) {
if (*data != 0) {
/* set the data line directly, ignore the setting from UCG_CFG_CD */
if (*data == 1) {
gpio_set_level( ucg->pin_list[UCG_PIN_CD], 0 );
} else {
gpio_set_level( ucg->pin_list[UCG_PIN_CD], 1 );
}
}
data++;
send_byte( hal, *data );
data++;
arg--;
}
break;
}
return 1;
}