Compare commits
11 Commits
wip/pico-u
...
cja/eink
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
af0ecf15d5 | ||
|
|
217f4938a5 | ||
|
|
3d3787603e | ||
|
|
4a06478565 | ||
|
|
0ebf876685 | ||
|
|
fdb81df3ca | ||
|
|
fa533f12f3 | ||
|
|
062a850357 | ||
|
|
18488d2fd0 | ||
|
|
4ba72d9cc0 | ||
|
|
a49b928dc1 |
@@ -509,6 +509,8 @@ HAL_StatusTypeDef HAL_SPI_Transmit(SPI_HandleTypeDef *hspi, uint8_t *pData, uint
|
||||
* @param Timeout: Timeout duration
|
||||
* @retval HAL status
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <trace.h>
|
||||
HAL_StatusTypeDef HAL_SPI_Receive(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout)
|
||||
{
|
||||
__IO uint16_t tmpreg;
|
||||
@@ -527,9 +529,12 @@ HAL_StatusTypeDef HAL_SPI_Receive(SPI_HandleTypeDef *hspi, uint8_t *pData, uint1
|
||||
return HAL_SPI_TransmitReceive(hspi,pData,pData,Size,Timeout);
|
||||
}
|
||||
|
||||
TRACE;
|
||||
/* Process Locked */
|
||||
__HAL_LOCK(hspi);
|
||||
|
||||
TRACE;
|
||||
|
||||
hspi->State = HAL_SPI_STATE_BUSY_RX;
|
||||
hspi->ErrorCode = HAL_SPI_ERROR_NONE;
|
||||
hspi->pRxBuffPtr = pData;
|
||||
@@ -546,6 +551,9 @@ HAL_StatusTypeDef HAL_SPI_Receive(SPI_HandleTypeDef *hspi, uint8_t *pData, uint1
|
||||
hspi->RxXferCount--;
|
||||
}
|
||||
|
||||
|
||||
TRACE;
|
||||
|
||||
/* Set the Rx Fido threshold */
|
||||
if (hspi->Init.DataSize > SPI_DATASIZE_8BIT) {
|
||||
/* set fiforxthreshold according the reception data length: 16bit */
|
||||
@@ -555,20 +563,35 @@ HAL_StatusTypeDef HAL_SPI_Receive(SPI_HandleTypeDef *hspi, uint8_t *pData, uint1
|
||||
SET_BIT(hspi->Instance->CR2, SPI_RXFIFO_THRESHOLD);
|
||||
}
|
||||
|
||||
|
||||
TRACE;
|
||||
|
||||
/* Configure communication direction 1Line and enabled SPI if needed */
|
||||
if (hspi->Init.Direction == SPI_DIRECTION_1LINE) {
|
||||
SPI_1LINE_RX(hspi);
|
||||
}
|
||||
|
||||
|
||||
TRACE;
|
||||
|
||||
/* Check if the SPI is already enabled */
|
||||
if ((hspi->Instance->CR1 & SPI_CR1_SPE) != SPI_CR1_SPE) {
|
||||
/* Enable SPI peripheral */
|
||||
__HAL_SPI_ENABLE(hspi);
|
||||
}
|
||||
|
||||
|
||||
TRACE;
|
||||
|
||||
/* Receive data in 8 Bit mode */
|
||||
if (hspi->Init.DataSize <= SPI_DATASIZE_8BIT) {
|
||||
|
||||
TRACE;
|
||||
|
||||
while (hspi->RxXferCount > 1) {
|
||||
|
||||
TRACE;
|
||||
|
||||
/* Wait until the RXNE flag */
|
||||
if (SPI_WaitFlagStateUntilTimeout(hspi, SPI_FLAG_RXNE, SPI_FLAG_RXNE, Timeout) != HAL_OK) {
|
||||
return HAL_TIMEOUT;
|
||||
@@ -588,6 +611,9 @@ HAL_StatusTypeDef HAL_SPI_Receive(SPI_HandleTypeDef *hspi, uint8_t *pData, uint1
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TRACE;
|
||||
|
||||
/* Enable CRC Transmission */
|
||||
if (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE) {
|
||||
hspi->Instance->CR1 |= SPI_CR1_CRCNEXT;
|
||||
@@ -598,6 +624,9 @@ HAL_StatusTypeDef HAL_SPI_Receive(SPI_HandleTypeDef *hspi, uint8_t *pData, uint1
|
||||
return HAL_TIMEOUT;
|
||||
}
|
||||
|
||||
|
||||
TRACE;
|
||||
|
||||
/* Receive last data in 16 Bit mode */
|
||||
if (hspi->Init.DataSize > SPI_DATASIZE_8BIT) {
|
||||
*((uint16_t*)hspi->pRxBuffPtr) = hspi->Instance->DR;
|
||||
|
||||
@@ -158,3 +158,42 @@ int gpio_get(unsigned nr)
|
||||
return HAL_GPIO_ReadPin(port_to_pointer(GPIO_PORT(nr)), 1 << GPIO_PIN(nr));
|
||||
}
|
||||
|
||||
#ifdef WITH_LIB_CONSOLE
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <lib/console.h>
|
||||
|
||||
static int cmd_stgpio(int argc, const cmd_args *argv)
|
||||
{
|
||||
if (argc >= 3) {
|
||||
char port = toupper(argv[2].str[0]);
|
||||
int pin = atoi(&argv[2].str[1]);
|
||||
uint32_t nr = ((port - 'A') << 8) | (pin & 0xff);
|
||||
|
||||
if (argc == 4 && !strcmp(argv[1].str,"set")) {
|
||||
unsigned int value = argv[3].u;
|
||||
|
||||
gpio_set(nr, value);
|
||||
return 0;
|
||||
} else if (argc == 3 && !strcmp(argv[1].str,"get")) {
|
||||
printf("gpio %c%d: %d\n", port, pin, gpio_get(nr));
|
||||
return 0;
|
||||
} else {
|
||||
goto print_usage;
|
||||
}
|
||||
}
|
||||
|
||||
print_usage:
|
||||
printf("stgpio set <gpio [A-K][0-15]> <value>\n");
|
||||
printf("stgpio get <gpio [A-K][0-15]>\n");
|
||||
putchar('\n');
|
||||
|
||||
return 0;
|
||||
}
|
||||
STATIC_COMMAND_START
|
||||
STATIC_COMMAND("stgpio", "wrapper for gpio commands with ST gpio naming conventions of [A-K][1-15]", &cmd_stgpio)
|
||||
STATIC_COMMAND_END(stgpio);
|
||||
|
||||
#endif
|
||||
|
||||
274
platform/stm32f7xx/include/platform/spi.h
Normal file
274
platform/stm32f7xx/include/platform/spi.h
Normal file
@@ -0,0 +1,274 @@
|
||||
#pragma once
|
||||
#include <err.h>
|
||||
#include <compiler.h>
|
||||
#include <platform/stm32.h>
|
||||
#include <kernel/mutex.h>
|
||||
|
||||
struct spi_bus {
|
||||
SPI_TypeDef *spi;
|
||||
mutex_t lock;
|
||||
};
|
||||
|
||||
#define INVALID_SPI_BUS -1
|
||||
|
||||
status_t spi_init(SPI_HandleTypeDef *handle);
|
||||
status_t spi_write(SPI_HandleTypeDef *handle, uint8_t *data, size_t len, uint32_t cs);
|
||||
status_t spi_read(SPI_HandleTypeDef *handle, uint8_t *data, size_t len, uint32_t cs);
|
||||
status_t spi_transaction(SPI_HandleTypeDef *handle, uint8_t *wdata, uint8_t *rdata, size_t len, uint32_t cs);
|
||||
|
||||
// Structure definitions for the STM32F7 spi controller. The intention is to point stm32f7_spi_t
|
||||
// at one of the spi base addresses defines such as SPI1
|
||||
//
|
||||
// ex: volatile stm32f7_spi_t *spi2 = (stm32f7_spi_t *) SPI2;
|
||||
|
||||
typedef struct {
|
||||
uint16_t cpha:1;
|
||||
uint16_t cpol:1;
|
||||
uint16_t mstr:1;
|
||||
uint16_t br:3;
|
||||
uint16_t spe:1;
|
||||
uint16_t lsb_first:1;
|
||||
uint16_t ssi:1;
|
||||
uint16_t ssm:1;
|
||||
uint16_t rx_only:1;
|
||||
uint16_t crcl:1;
|
||||
uint16_t crc_next:1;
|
||||
uint16_t crc_en:1;
|
||||
uint16_t bidi_oe:1;
|
||||
uint16_t bidi_mode:1;
|
||||
} SPIx_CR1_t;
|
||||
|
||||
typedef struct {
|
||||
uint16_t rxdmaen:1;
|
||||
uint16_t txdmaen:1;
|
||||
uint16_t ssoe:1;
|
||||
uint16_t nssp:1;
|
||||
uint16_t frf:1;
|
||||
uint16_t errie:1;
|
||||
uint16_t rxneie:1;
|
||||
uint16_t txeie:1;
|
||||
uint16_t ds:4;
|
||||
uint16_t frxth:1;
|
||||
uint16_t ldma_rx:1;
|
||||
uint16_t ldma_tx:1;
|
||||
uint16_t __reserved0:1;
|
||||
} SPIx_CR2_t;
|
||||
|
||||
typedef struct {
|
||||
uint16_t rxne:1;
|
||||
uint16_t txe:1;
|
||||
uint16_t chside:1;
|
||||
uint16_t udr:1;
|
||||
uint16_t crcerr:1;
|
||||
uint16_t modf:1;
|
||||
uint16_t ovr:1;
|
||||
uint16_t bsy:1;
|
||||
uint16_t fre:1;
|
||||
uint16_t frlvl:2;
|
||||
uint16_t ftlvl:2;
|
||||
uint16_t __reserved0:3;
|
||||
} SPIx_SR_t;
|
||||
|
||||
typedef struct {
|
||||
SPIx_CR1_t CR1;
|
||||
uint16_t __reserved0;
|
||||
SPIx_CR2_t CR2;
|
||||
uint16_t __reserved1;
|
||||
SPIx_SR_t SR;
|
||||
uint16_t __reserved2;
|
||||
uint16_t DR;
|
||||
} stm32f7_spi_t;
|
||||
|
||||
enum cpha {
|
||||
cpha_first_transition = 0x0,
|
||||
cpha_second_transition = 0x1,
|
||||
};
|
||||
|
||||
enum cpol {
|
||||
cpol_clk_idle_low = 0x0,
|
||||
cpol_clk_idle_high = 0x1,
|
||||
};
|
||||
|
||||
enum mstr {
|
||||
mstr_spi_slave = 0x0,
|
||||
mstr_spi_master = 0x1,
|
||||
};
|
||||
|
||||
enum br {
|
||||
fpclk_div_2 = 0b000,
|
||||
fpclk_div_4 = 0b001,
|
||||
fpclk_div_8 = 0b010,
|
||||
fpclk_div_16 = 0b011,
|
||||
fpclk_div_32 = 0b100,
|
||||
fpclk_div_64 = 0b101,
|
||||
fpclk_div_128 = 0b110,
|
||||
fpclk_div_256 = 0b111,
|
||||
};
|
||||
|
||||
enum spe {
|
||||
spe_spi_disable = 0x0,
|
||||
spe_spi_enabled = 0x1,
|
||||
};
|
||||
|
||||
enum ssm {
|
||||
ssm_disabled = 0x0,
|
||||
ssm_enabled = 0x1,
|
||||
};
|
||||
|
||||
enum rxonly {
|
||||
rxonly_full_duplex = 0x0,
|
||||
rxonly_output_disabled = 0x1,
|
||||
};
|
||||
|
||||
enum crcl {
|
||||
crcl_8bit = 0x0,
|
||||
crcl_16bit = 0x1,
|
||||
};
|
||||
|
||||
enum crcnext {
|
||||
crcnext_tx_buf_next = 0x0,
|
||||
crcnext_tx_crc_next = 0x1,
|
||||
};
|
||||
|
||||
enum crcen {
|
||||
hw_crc_disable = 0x0,
|
||||
hw_crc_enable = 0x1,
|
||||
};
|
||||
|
||||
enum bidioe {
|
||||
bidi_output_disable = 0x0,
|
||||
bidi_output_enable = 0x1,
|
||||
};
|
||||
|
||||
enum bidimode {
|
||||
bidi_mode_2 = 0x0,
|
||||
bidi_mode_1 = 0x1,
|
||||
};
|
||||
|
||||
enum rxdmaen {
|
||||
rx_dma_disabled = 0x0,
|
||||
rx_dma_enabled = 0x1,
|
||||
};
|
||||
|
||||
enum txdmaen {
|
||||
tx_dma_disabled = 0x0,
|
||||
tx_dma_enabled = 0x1,
|
||||
};
|
||||
|
||||
enum ssoe {
|
||||
ss_output_disabled = 0x0,
|
||||
ss_output_enabled = 0x1,
|
||||
};
|
||||
|
||||
enum nssp {
|
||||
nss_pulse_disable = 0x0,
|
||||
nss_pulse_enable = 0x1,
|
||||
};
|
||||
|
||||
enum frf {
|
||||
motorola_mode = 0x0,
|
||||
ti_mode = 0x1,
|
||||
};
|
||||
|
||||
enum errie {
|
||||
err_int_mask = 0x0,
|
||||
err_int_enable = 0x1,
|
||||
};
|
||||
|
||||
enum rxneie {
|
||||
rxne_int_mask = 0x0,
|
||||
rxne_int_enable = 0x1,
|
||||
};
|
||||
|
||||
enum txeie {
|
||||
txe_int_mask = 0x0,
|
||||
txe_int_enable = 0x1,
|
||||
};
|
||||
|
||||
enum ds {
|
||||
data_size_4bit = 0b0011,
|
||||
data_size_5bit = 0b0100,
|
||||
data_size_6bit = 0b0101,
|
||||
data_size_7bit = 0b0110,
|
||||
data_size_8bit = 0b0111,
|
||||
data_size_9bit = 0b1000,
|
||||
data_size_10bit = 0b1001,
|
||||
data_size_11bit = 0b1010,
|
||||
data_size_12bit = 0b1011,
|
||||
data_size_13bit = 0b1100,
|
||||
data_size_14bit = 0b1101,
|
||||
data_size_15bit = 0b1110,
|
||||
data_size_16bit = 0b1111,
|
||||
};
|
||||
|
||||
enum frxth {
|
||||
rxne_event_fifo_1_2 = 0x0,
|
||||
rxne_event_fifo_1_4 = 0x1,
|
||||
};
|
||||
|
||||
enum ldma_rx {
|
||||
data_rx_even = 0x0,
|
||||
data_rx_odd = 0x1,
|
||||
};
|
||||
|
||||
enum ldma_tx {
|
||||
data_tx_even = 0x0,
|
||||
data_tx_odd = 0x1,
|
||||
};
|
||||
|
||||
enum sr_rxne {
|
||||
sr_rx_buf_empty = 0x0,
|
||||
sr_rx_buf_not_empty = 0x1,
|
||||
};
|
||||
|
||||
enum sr_txne {
|
||||
sr_tx_buf_empty = 0x0,
|
||||
sr_tx_buf_not_empty = 0x1,
|
||||
};
|
||||
|
||||
// CHSIDE unused in SPI mode
|
||||
// UDR unused in SPI mode
|
||||
|
||||
enum crcerr {
|
||||
sr_crc_match = 0x0,
|
||||
sr_crc_mismatch = 0x1,
|
||||
};
|
||||
|
||||
enum modf {
|
||||
sr_mode_fault = 0x0,
|
||||
sr_no_mode_fault = 0x1,
|
||||
};
|
||||
|
||||
enum ovr {
|
||||
sr_no_overrun = 0x0,
|
||||
sr_overrun = 0x1,
|
||||
};
|
||||
|
||||
enum bsy {
|
||||
sr_not_busy = 0x0,
|
||||
sr_busy = 0x1,
|
||||
};
|
||||
|
||||
enum fre {
|
||||
sr_no_fre = 0x0,
|
||||
sr_fre = 0x1,
|
||||
};
|
||||
|
||||
enum frlvl {
|
||||
sr_rx_fifo_empty = 0b00,
|
||||
sr_rx_fifo_1_4 = 0b01,
|
||||
sr_rx_fifo_1_2 = 0b10,
|
||||
sr_rx_fifo_full = 0b11,
|
||||
};
|
||||
|
||||
enum ftlvl {
|
||||
sr_tx_fifo_empty = 0b00,
|
||||
sr_tx_fifo_1_4 = 0b01,
|
||||
sr_tx_fifo_1_2 = 0b10,
|
||||
sr_tx_fifo_full = 0b11,
|
||||
};
|
||||
|
||||
STATIC_ASSERT(__builtin_offsetof(stm32f7_spi_t, CR1) == 0x0);
|
||||
STATIC_ASSERT(__builtin_offsetof(stm32f7_spi_t, CR2) == 0x4);
|
||||
STATIC_ASSERT(__builtin_offsetof(stm32f7_spi_t, SR) == 0x8);
|
||||
STATIC_ASSERT(__builtin_offsetof(stm32f7_spi_t, DR) == 0xC);
|
||||
@@ -48,11 +48,12 @@ MODULE_SRCS += \
|
||||
$(LOCAL_DIR)/usbc.c \
|
||||
$(LOCAL_DIR)/vectab.c \
|
||||
$(LOCAL_DIR)/sdram.c \
|
||||
$(LOCAL_DIR)/spi.c \
|
||||
$(LOCAL_DIR)/qspi.c
|
||||
|
||||
# use a two segment memory layout, where all of the read-only sections
|
||||
# of the binary reside in rom, and the read/write are in memory. The
|
||||
# ROMBASE, MEMBASE, and MEMSIZE make variables are required to be set
|
||||
# use a two segment memory layout, where all of the read-only sections
|
||||
# of the binary reside in rom, and the read/write are in memory. The
|
||||
# ROMBASE, MEMBASE, and MEMSIZE make variables are required to be set
|
||||
# for the linker script to be generated properly.
|
||||
#
|
||||
LINKER_SCRIPT += \
|
||||
|
||||
317
platform/stm32f7xx/spi.c
Normal file
317
platform/stm32f7xx/spi.c
Normal file
@@ -0,0 +1,317 @@
|
||||
#include <assert.h>
|
||||
#include <debug.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <target/gpioconfig.h>
|
||||
#include <platform/spi.h>
|
||||
#include <platform/stm32.h>
|
||||
|
||||
static struct spi_bus spi_busses[] = {
|
||||
{ .spi = SPI1 },
|
||||
{ .spi = SPI2 },
|
||||
{ .spi = SPI3 },
|
||||
{ .spi = SPI4 },
|
||||
{ .spi = SPI5 },
|
||||
{ .spi = SPI6 }
|
||||
};
|
||||
|
||||
static inline int get_bus_idx(SPI_TypeDef *spi)
|
||||
{
|
||||
for (unsigned int i = 0; i < (sizeof(spi_busses)/sizeof(spi_busses[0])); i++) {
|
||||
if (spi_busses[i].spi == spi) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return INVALID_SPI_BUS;
|
||||
}
|
||||
|
||||
static bool wait_for_bus_ready(SPI_HandleTypeDef *handle)
|
||||
{
|
||||
size_t timeout = 1024;
|
||||
while (timeout && (HAL_SPI_GetState(handle) != HAL_SPI_STATE_READY)) {
|
||||
timeout--;
|
||||
}
|
||||
|
||||
if (timeout == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
status_t spi_init (SPI_HandleTypeDef *handle)
|
||||
{
|
||||
DEBUG_ASSERT(handle);
|
||||
|
||||
status_t ret = NO_ERROR;
|
||||
int bus = get_bus_idx(handle->Instance);
|
||||
|
||||
if (bus == INVALID_SPI_BUS) {
|
||||
return ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
mutex_init(&(spi_busses[bus].lock));
|
||||
if (HAL_SPI_Init(handle) != HAL_OK) {
|
||||
ret = ERR_GENERIC;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
status_t spi_write(SPI_HandleTypeDef *handle, uint8_t *data, size_t len, uint32_t cs)
|
||||
{
|
||||
DEBUG_ASSERT(handle);
|
||||
DEBUG_ASSERT(data);
|
||||
DEBUG_ASSERT(len);
|
||||
|
||||
status_t ret = NO_ERROR;
|
||||
int bus = get_bus_idx(handle->Instance);
|
||||
int cs_val;
|
||||
bool use_soft_nss = ((handle->Init.NSS == SPI_NSS_SOFT) && cs);
|
||||
|
||||
if (bus == INVALID_SPI_BUS) {
|
||||
return ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
mutex_acquire(&(spi_busses[bus].lock));
|
||||
if (use_soft_nss) {
|
||||
cs_val = gpio_get(cs);
|
||||
gpio_set(cs, !cs_val);
|
||||
}
|
||||
|
||||
HAL_StatusTypeDef foo;
|
||||
|
||||
/* The lock may have been released while the hardware is still processing a transaction */
|
||||
if (!wait_for_bus_ready(handle)) {
|
||||
ret = ERR_BUSY;
|
||||
} else {
|
||||
if ((foo = HAL_SPI_Transmit(handle, data, len, HAL_MAX_DELAY)) != HAL_OK) {
|
||||
ret = ERR_IO;
|
||||
}
|
||||
}
|
||||
|
||||
if (use_soft_nss) {
|
||||
gpio_set(cs, cs_val);
|
||||
}
|
||||
mutex_release(&(spi_busses[bus].lock));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
status_t spi_read(SPI_HandleTypeDef *handle, uint8_t *data, size_t len, uint32_t cs)
|
||||
{
|
||||
DEBUG_ASSERT(handle);
|
||||
DEBUG_ASSERT(data);
|
||||
DEBUG_ASSERT(len);
|
||||
|
||||
status_t ret = NO_ERROR;
|
||||
int bus = get_bus_idx(handle->Instance);
|
||||
int cs_val;
|
||||
bool use_soft_nss = (handle->Init.NSS == SPI_NSS_SOFT);
|
||||
|
||||
if (bus == INVALID_SPI_BUS) {
|
||||
return ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
mutex_acquire(&(spi_busses[bus].lock));
|
||||
if (use_soft_nss) {
|
||||
cs_val = gpio_get(cs);
|
||||
gpio_set(cs, !cs_val);
|
||||
}
|
||||
|
||||
if (HAL_SPI_Receive(handle, data, len, HAL_MAX_DELAY) != HAL_OK) {
|
||||
ret = ERR_IO;
|
||||
}
|
||||
|
||||
if (use_soft_nss) {
|
||||
gpio_set(cs, cs_val);
|
||||
}
|
||||
mutex_release(&(spi_busses[bus].lock));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
status_t spi_transaction(SPI_HandleTypeDef *handle, uint8_t *wdata, uint8_t *rdata, size_t len, uint32_t cs)
|
||||
{
|
||||
DEBUG_ASSERT(handle);
|
||||
DEBUG_ASSERT(wdata);
|
||||
DEBUG_ASSERT(rdata);
|
||||
DEBUG_ASSERT(len);
|
||||
|
||||
status_t ret = NO_ERROR;
|
||||
int bus = get_bus_idx(handle->Instance);
|
||||
|
||||
if (bus == INVALID_SPI_BUS) {
|
||||
return ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
mutex_acquire(&(spi_busses[bus].lock));
|
||||
if (handle->Init.NSS == SPI_NSS_SOFT) {
|
||||
gpio_set(cs, (handle->Init.CLKPolarity == 0) ? GPIO_PIN_RESET : GPIO_PIN_SET);
|
||||
}
|
||||
|
||||
if (HAL_SPI_TransmitReceive(handle, wdata, rdata, len, HAL_MAX_DELAY) != HAL_OK) {
|
||||
ret = ERR_IO;
|
||||
}
|
||||
|
||||
if (handle->Init.NSS == SPI_NSS_SOFT) {
|
||||
gpio_set(cs, (handle->Init.CLKPolarity == 0) ? GPIO_PIN_SET : GPIO_PIN_RESET);
|
||||
}
|
||||
mutex_release(&(spi_busses[bus].lock));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if WITH_LIB_CONSOLE
|
||||
#include <lib/console.h>
|
||||
|
||||
/* Bus configurations for testing. Although it requires a recompilation per setting tweaked,
|
||||
* it saves us from having to write a great deal of configuration code via an awkward console
|
||||
* interface with many arguments.
|
||||
*
|
||||
* XXX: This doesn't handle soft NSS on its own.
|
||||
*/
|
||||
|
||||
// This test code is primarily for DartuinoP0 and the GPIO will only exist for that target
|
||||
#define STM32F7_SPI_BUS_CNT 6
|
||||
static SPI_HandleTypeDef handles[STM32F7_SPI_BUS_CNT] = {
|
||||
[0] = { 0 },
|
||||
[1] = {
|
||||
.Instance = SPI2,
|
||||
.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4,
|
||||
.Init.Direction = SPI_DIRECTION_1LINE,
|
||||
.Init.CLKPhase = SPI_PHASE_1EDGE,
|
||||
.Init.CLKPolarity = SPI_POLARITY_LOW,
|
||||
.Init.DataSize = SPI_DATASIZE_8BIT,
|
||||
.Init.FirstBit = SPI_FIRSTBIT_LSB,
|
||||
.Init.TIMode = SPI_TIMODE_DISABLE,
|
||||
.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE,
|
||||
.Init.CRCPolynomial = 7,
|
||||
.Init.NSS = SPI_NSS_SOFT,
|
||||
.Init.Mode = SPI_MODE_MASTER,
|
||||
},
|
||||
[2] = { 0 },
|
||||
[3] = { 0 },
|
||||
[4] = { 0 },
|
||||
[5] = {
|
||||
.Instance = SPI5,
|
||||
.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4,
|
||||
.Init.Direction = SPI_DIRECTION_1LINE,
|
||||
.Init.CLKPhase = SPI_PHASE_1EDGE,
|
||||
.Init.CLKPolarity = SPI_POLARITY_LOW,
|
||||
.Init.DataSize = SPI_DATASIZE_8BIT,
|
||||
.Init.FirstBit = SPI_FIRSTBIT_MSB,
|
||||
.Init.TIMode = SPI_TIMODE_DISABLE,
|
||||
.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE,
|
||||
.Init.CRCPolynomial = 7,
|
||||
.Init.NSS = SPI_NSS_SOFT,
|
||||
.Init.Mode = SPI_MODE_MASTER,
|
||||
},
|
||||
};
|
||||
|
||||
// GPIO to whack for soft chip select
|
||||
static unsigned int handle_nss[STM32F7_SPI_BUS_CNT] = {
|
||||
[5] = GPIO(GPIO_PORT_K, 0), // NRF_CS on Dartuino P0
|
||||
};
|
||||
|
||||
|
||||
/* Check if bus is valid, initialize it if needed */
|
||||
static inline bool check_bus(uint8_t bus)
|
||||
{
|
||||
if (bus < STM32F7_SPI_BUS_CNT && handles[bus].Instance == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (HAL_SPI_GetState(&handles[bus]) == HAL_SPI_STATE_RESET) {
|
||||
HAL_SPI_Init(&handles[bus]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void print_spi_usage(void)
|
||||
{
|
||||
printf("spi read <bus> <len>\n");
|
||||
printf("\tRead <len> bytes from <bus>\n");
|
||||
printf("spi spew <bus> <len> <n> <delay>\n");
|
||||
printf("\tWrite <len> bytes <n> times with a delay of <delay> ms between over <bus>\n");
|
||||
}
|
||||
|
||||
#define IS_CMD(_str, _argc) (argc >= _argc && (strcmp(_str, argv[1].str) == 0))
|
||||
static int cmd_spi(int argc, const cmd_args *argv)
|
||||
{
|
||||
status_t ret = NO_ERROR;
|
||||
// spi read <bus> <len>
|
||||
if (IS_CMD("read", 4)) {
|
||||
uint8_t bus = argv[2].i;
|
||||
size_t len = MIN(1024, argv[3].i);
|
||||
uint8_t *data = (uint8_t *)malloc(len);
|
||||
|
||||
if (!data) {
|
||||
ret = ERR_NO_MEMORY;
|
||||
goto read_err;
|
||||
}
|
||||
|
||||
if (!check_bus(bus)) {
|
||||
printf("Error: bus %u is invalid\n", bus);
|
||||
ret = ERR_INVALID_ARGS;
|
||||
goto read_err;
|
||||
}
|
||||
|
||||
if (spi_read(&handles[bus], data, len, handle_nss[bus]) != NO_ERROR) {
|
||||
printf("spi read error\n");
|
||||
ret = ERR_IO;
|
||||
goto read_err;
|
||||
}
|
||||
|
||||
hexdump8(data, len);
|
||||
|
||||
read_err:
|
||||
free(data);
|
||||
|
||||
// spi spew <bus> <len> <iterations> <delay>
|
||||
} else if (IS_CMD("spew", 6)) {
|
||||
uint8_t bus = argv[2].i;
|
||||
size_t len = MIN(1024, argv[3].i);
|
||||
uint32_t cnt = argv[4].i;
|
||||
uint32_t delay = argv[5].i;
|
||||
uint8_t *data = (uint8_t *)malloc(len);
|
||||
|
||||
if (cnt == 0) {
|
||||
cnt = UINT32_MAX;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < len; i++) {
|
||||
data[i] = i % 255;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < cnt; i++) {
|
||||
int spi_ret;
|
||||
if ((spi_ret = spi_write(&handles[bus], data, len, handle_nss[bus])) != NO_ERROR) {
|
||||
printf("spi write error: %d\n", spi_ret);
|
||||
ret = ERR_IO;
|
||||
goto spew_err;
|
||||
}
|
||||
|
||||
if (delay > 0) {
|
||||
thread_sleep(delay);
|
||||
}
|
||||
}
|
||||
|
||||
spew_err:
|
||||
free(data);
|
||||
} else {
|
||||
print_spi_usage();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
STATIC_COMMAND_START
|
||||
STATIC_COMMAND("spi", "spi commands for stm32f7", &cmd_spi)
|
||||
STATIC_COMMAND_END(spi);
|
||||
|
||||
|
||||
|
||||
#endif // WITH_LIB_CONSOLE
|
||||
@@ -3,5 +3,5 @@
|
||||
export PROJECT=dartuinoP0-test
|
||||
|
||||
make -j8 &&
|
||||
openocd -f interface/stlink-v2.cfg -f board/stm32756g_eval.cfg \
|
||||
openocd -f interface/stlink-v2.cfg -f target/stm32f7x.cfg \
|
||||
-c "program build-$PROJECT/lk.bin reset exit 0x08000000"
|
||||
|
||||
@@ -3,5 +3,5 @@
|
||||
export PROJECT=stm32f746g-disco-test
|
||||
|
||||
make -j8 &&
|
||||
openocd -f interface/stlink-v2-1.cfg -f board/stm32756g_eval.cfg \
|
||||
openocd -f interface/stlink-v2-1.cfg -f board/stm32f7discovery.cfg \
|
||||
-c "program build-$PROJECT/lk.bin reset exit 0x08000000"
|
||||
|
||||
922
target/dartuinoP0/display/eink.c
Normal file
922
target/dartuinoP0/display/eink.c
Normal file
@@ -0,0 +1,922 @@
|
||||
#include <assert.h>
|
||||
#include <err.h>
|
||||
#include <debug.h>
|
||||
#include <rand.h>
|
||||
#include <stdlib.h>
|
||||
#include <trace.h>
|
||||
#include <dev/display.h>
|
||||
#include <kernel/spinlock.h>
|
||||
#include <platform/timer.h>
|
||||
#include <platform/gpio.h>
|
||||
#include <target/gpioconfig.h>
|
||||
#include <string.h>
|
||||
// TODO The eink driver should not include stm headers. We likely need INIT to store
|
||||
// a spihandle and then spi functions use it some other way
|
||||
#include <stm32f7xx.h>
|
||||
#include <platform/spi.h>
|
||||
#include <platform.h>
|
||||
|
||||
/* The following tables are copied verbatim with comments from the verily driver */
|
||||
// TODO(nicholasewalt): Update LUTs once they are provided by Eink.
|
||||
// TODO(nicholasewalt): Investigate truncating and compressing LUTs. Current
|
||||
// tables are only 62 frames long and are highly compressible, however new
|
||||
// tables will likely have less potential gains.
|
||||
// FTLUT
|
||||
// White REAGL LUT for K/W/Gray mode.
|
||||
//
|
||||
// F/T waveform for up to 128 frames, 1 byte per frame.
|
||||
//
|
||||
// For one frame:
|
||||
//
|
||||
// | D7 D6 | D5 D4 | D3 D2 | D1 D0 |
|
||||
// |--------------+--------------+--------------+--------------|
|
||||
// | F1_KF[1:0] | F1_KT[1:0] | F1_WF[1:0] | F1_WT[1:0] |
|
||||
//
|
||||
// NOTE: These bit definitions are not explained in more detail in the
|
||||
// datasheet.
|
||||
//
|
||||
static uint8_t lut_ft[128] = {
|
||||
0x55, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55,
|
||||
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
|
||||
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0xAA,
|
||||
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x5A, 0x5A,
|
||||
0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A,
|
||||
0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
// KWG_VCOM
|
||||
// VCOM LUT for K/W/Gray mode.
|
||||
//
|
||||
// VCOM LUT for up to 128 frames, 2 bits per frame.
|
||||
//
|
||||
// For one frame:
|
||||
//
|
||||
// | D7 D6 | D5 D4 | D3 D2 | D1 D0 |
|
||||
// |--------------+--------------+--------------+--------------|
|
||||
// | VCOM1[1:0] | VCOM2[1:0] | VCOM3[1:0] | VCOM4[1:0] |
|
||||
//
|
||||
// VCOM(1~128)[1:0]: VCOM voltage level of Frame 1~128, respectively.
|
||||
// 00b: VCOM output VCOMDC
|
||||
// 01b: VCOM output VSH+VCOM_DC (VCOMH)
|
||||
// 10b: VCOM output VSL+VCOM_DC (VCOML)
|
||||
// 11b: VCOM output floating.
|
||||
//
|
||||
static uint8_t lut_kwg_vcom[32] = {
|
||||
0x55, 0x6A, 0xA5, 0x55, 0x55, 0x55, 0x55, 0x55, 0x56, 0xAA, 0xAA,
|
||||
0xAA, 0xAA, 0xAA, 0xAA, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
// KWG_LUT
|
||||
// Source LUT for K/W/Gray mode.
|
||||
// NOTE: This LUT was ripped from the Hulk Jig firmware, however it did not
|
||||
// include waveforms for transitioning into or out of gray*. nicholasewalt@
|
||||
// added preliminary white to gray* transitions, though they do not have good
|
||||
// mixing and other gray* transitions are still unsupported.
|
||||
//
|
||||
// Pixel waveforms for up to 128 frames, 4 bytes per frame.
|
||||
// If waveforms of one frame are all 11b, the update precedue will stop.
|
||||
//
|
||||
// For one frame:
|
||||
//
|
||||
// | D7 D6 | D5 D4 | D3 D2 | D1 D0 |
|
||||
// |--------------+--------------+--------------+--------------|
|
||||
// | F1_P0C0[1:0] | F1_P0C1[1:0] | F1_P0C2[1:0] | F1_P0C3[1:0] |
|
||||
// | F1_P1C0[1:0] | F1_P1C1[1:0] | F1_P1C2[1:0] | F1_P1C3[1:0] |
|
||||
// | F1_P2C0[1:0] | F1_P2C1[1:0] | F1_P2C2[1:0] | F1_P2C3[1:0] |
|
||||
// | F1_P3C0[1:0] | F1_P3C1[1:0] | F1_P3C2[1:0] | F1_P3C3[1:0] |
|
||||
//
|
||||
// P0C0/P0C1/P0C2/P0C3: black to black/gray1/gray2/white respectively
|
||||
// P1C0/P1C1/P1C2/P1C3: gray1 to black/gray1/gray2/white respectively
|
||||
// P2C0/P2C1/P2C2/P2C3: gray2 to black/gray1/gray2/white respectively
|
||||
// P3C0/P3C1/P3C2/P3C3: white to black/gray1/gray2/white respectively
|
||||
//
|
||||
// P0~3C0~3[1:0]:
|
||||
// 00b: GND
|
||||
// 01b: VSH
|
||||
// 10b: VSL
|
||||
// 11b: VSHR
|
||||
//
|
||||
static uint8_t lut_kwg[512] = {
|
||||
0x41, 0x81, 0x81, 0x81, 0x41, 0x81, 0x81, 0x81, 0x41, 0x81, 0x81, 0x81,
|
||||
0x41, 0x81, 0x81, 0x81, 0x41, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x82,
|
||||
0x81, 0x81, 0x81, 0x82, 0x81, 0x81, 0x81, 0x82, 0x81, 0x81, 0x81, 0x82,
|
||||
0x81, 0x81, 0x81, 0x82, 0x42, 0x42, 0x42, 0x41, 0x42, 0x42, 0x42, 0x41,
|
||||
0x42, 0x42, 0x42, 0x41, 0x42, 0x42, 0x42, 0x41, 0x42, 0x42, 0x42, 0x41,
|
||||
0x42, 0x42, 0x42, 0x41, 0x42, 0x42, 0x42, 0x41, 0x42, 0x42, 0x42, 0x41,
|
||||
0x42, 0x42, 0x42, 0x41, 0x42, 0x42, 0x42, 0x41, 0x42, 0x42, 0x42, 0x41,
|
||||
0x42, 0x42, 0x42, 0x41, 0x42, 0x42, 0x42, 0x41, 0x42, 0x42, 0x42, 0x41,
|
||||
0x42, 0x42, 0x42, 0x41, 0x42, 0x42, 0x42, 0x41, 0x42, 0x42, 0x42, 0x41,
|
||||
0x42, 0x42, 0x42, 0x41, 0x42, 0x42, 0x42, 0x41, 0x42, 0x42, 0x42, 0x41,
|
||||
0x42, 0x42, 0x42, 0x41, 0x42, 0x42, 0x42, 0x41, 0x42, 0x42, 0x42, 0x41,
|
||||
0x42, 0x42, 0x42, 0x41, 0x42, 0x42, 0x42, 0x41, 0x82, 0x42, 0x42, 0x42,
|
||||
0x82, 0x42, 0x42, 0x42, 0x82, 0x42, 0x42, 0x42, 0x82, 0x42, 0x42, 0x42,
|
||||
0x82, 0x42, 0x42, 0x42, 0x82, 0x42, 0x42, 0x42, 0x82, 0x42, 0x42, 0x42,
|
||||
0x82, 0x42, 0x42, 0x42, 0x82, 0x42, 0x42, 0x42, 0x82, 0x42, 0x42, 0x42,
|
||||
0x82, 0x42, 0x42, 0x4a, 0x82, 0x42, 0x42, 0x4a, 0x82, 0x42, 0x42, 0x4a,
|
||||
0x82, 0x42, 0x42, 0x4a, 0x82, 0x42, 0x42, 0x4a, 0x82, 0x42, 0x42, 0x4a,
|
||||
0x82, 0x42, 0x42, 0x4a, 0x82, 0x42, 0x42, 0x4a, 0x82, 0x42, 0x42, 0x4a,
|
||||
0x82, 0x42, 0x42, 0x6a, 0x82, 0x42, 0x42, 0x6a, 0x82, 0x42, 0x42, 0x6a,
|
||||
0x82, 0x42, 0x42, 0x6a, 0x82, 0x42, 0x42, 0x6a, 0x82, 0x42, 0x42, 0x6a,
|
||||
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
|
||||
/* cja: end of imported LUTs */
|
||||
#define LOCAL_TRACE 0
|
||||
|
||||
#if WITH_LIB_CONSOLE
|
||||
#include <lib/console.h>
|
||||
SPI_HandleTypeDef SpiHandle;
|
||||
bool spi_inited = false;
|
||||
spin_lock_t lock;
|
||||
spin_lock_saved_state_t state;
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
uint8_t byte0;
|
||||
// RST_N: Soft Reset
|
||||
// 0: Assert reset function : Booster OFF and Register data reset to its
|
||||
// default value
|
||||
// 1: No effect (default)
|
||||
uint8_t rst_n:1;
|
||||
// SHD_N: Booster Shutdown
|
||||
// 0: Booster shutdown and register data kept
|
||||
// 1: No booster shutdown (default)
|
||||
uint8_t shd_n:1;
|
||||
// SHL: Shift Left
|
||||
// 0: Shift right
|
||||
// 1: Shift left (default)
|
||||
uint8_t shl:1;
|
||||
// SDMD: Source Driver Mode Selection
|
||||
// 0: Rectangular mode
|
||||
// 1: Circle mode (default)
|
||||
uint8_t sdmd:1;
|
||||
// GDMD: Gate Driver Mode Selection
|
||||
// 0: Multiplexing gate mode (default)
|
||||
// 1: Normal mode
|
||||
uint8_t gdmd:1;
|
||||
uint8_t __rs0:1;
|
||||
// RES[1:0]: Resolution Setting
|
||||
// Bit definitions in PanelSettingRes enum.
|
||||
uint8_t res:2;
|
||||
};
|
||||
union {
|
||||
uint8_t byte1;
|
||||
// SFT[1:0]: Cardinal Neighbors setting. Set cardinal neighbors number for
|
||||
// REAGAL.
|
||||
// Bit definitions in PanelSettingsSft enum.
|
||||
uint8_t sft:2;
|
||||
// IMCP: Image copy setting
|
||||
// 0: “Copy new data to old data storage” disabled after display
|
||||
// 1: “Copy new data to old data storage” enabled after display (default)
|
||||
uint8_t imcp:1;
|
||||
uint8_t __rs1:4;
|
||||
// REG_EN: LUT selection
|
||||
// 0: Using LUT from OTP (default)
|
||||
// 1: Using LUT from internal register
|
||||
uint8_t reg_en:1;
|
||||
};
|
||||
} panel_setting_t;
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
uint8_t byte0;
|
||||
// Gate power selection
|
||||
// 0: External gate power from VGH/VGL pins
|
||||
// 1: Internal DC/DC function for generating VGH/VGL
|
||||
uint8_t vg_en:1;
|
||||
// Source power selection
|
||||
// 0: External source power from VDH/VDL pins
|
||||
// 1: Internal DC/DC function for generating VDH/VDL
|
||||
uint8_t vs_en:1;
|
||||
uint8_t __rs0:6;
|
||||
};
|
||||
|
||||
union {
|
||||
uint8_t byte1;
|
||||
// VG_LVL[1:0]: Gate Voltage Level selection
|
||||
// Bit definitions in power settings enum.
|
||||
uint8_t vg_lvl:2;
|
||||
// VCOM_HV: VCOM Voltage Level
|
||||
// 0: VCOMH=VSH+VCOMDC, VCOML=VSL+VCOMDC (default)
|
||||
// 1: VCOML=VGH, VCOML=VGL
|
||||
uint8_t vcom_hv:1;
|
||||
uint8_t __rs1:5;
|
||||
};
|
||||
|
||||
union {
|
||||
uint8_t byte2;
|
||||
// VSH_LVL[5:0]: Internal positive source voltage level for K/W
|
||||
// (range: +2.4V ~ +11.0V / step:0.2V / default : +10.0V)
|
||||
uint8_t vsh_lvl:6;
|
||||
uint8_t __rs2:2;
|
||||
};
|
||||
|
||||
union {
|
||||
uint8_t byte3;
|
||||
// VSL_LVL[5:0]: Internal negative source voltage level for K/W
|
||||
// (range: -2.4V ~ -11.0V / step:0.2V / default : -10.0V)
|
||||
uint8_t vsl_lvl:6;
|
||||
uint8_t __rs3:2;
|
||||
};
|
||||
|
||||
union {
|
||||
uint8_t byte4;
|
||||
uint8_t vshr_lvl:6;
|
||||
uint8_t __rs4:2;
|
||||
};
|
||||
} pwr_settings_t;
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
uint8_t byte0;
|
||||
uint8_t btpha_min_off:3;
|
||||
uint8_t btpha_drive_strength:3;
|
||||
uint8_t btpha_soft_start:2;
|
||||
};
|
||||
|
||||
union {
|
||||
uint8_t byte1;
|
||||
uint8_t btphb_min_off:3;
|
||||
uint8_t btphb_drive_strength:3;
|
||||
uint8_t btphb_soft_start:2;
|
||||
};
|
||||
|
||||
union {
|
||||
uint8_t byte2;
|
||||
uint8_t btphc_min_off:3;
|
||||
uint8_t btphc_drive_strength:3;
|
||||
uint8_t __rs0:2;
|
||||
};
|
||||
} booster_settings_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t busy_n:1;
|
||||
uint8_t pof:1;
|
||||
uint8_t pon:1;
|
||||
uint8_t data_flag:1;
|
||||
uint8_t i2c_busyn:1;
|
||||
uint8_t i2c_err:1;
|
||||
uint8_t __rs0:2;
|
||||
} et011tt2_status_t;
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
uint8_t byte0;
|
||||
// DDX[1:0]: Data polarity
|
||||
// 0: Inverted
|
||||
// 1: Normal (default)
|
||||
uint8_t ddx:1;
|
||||
uint8_t __rs0:3;
|
||||
// VBD[1:0]: Border output selection
|
||||
uint8_t bdd:2;
|
||||
// BDV: Border DC Voltage control
|
||||
// 0: Border Output DC Voltage Function disabled (default)
|
||||
// 1: Border Output DC Voltage Function enabled
|
||||
uint8_t bdv:1;
|
||||
// BDZ: Border Hi-Z control
|
||||
// 0: Border Output Hi-Z disabled (default)
|
||||
// 1: Border Output Hi-Z enabled
|
||||
uint8_t bdz:1;
|
||||
};
|
||||
|
||||
union {
|
||||
uint8_t byte1;
|
||||
// CDI[9:0]: VCOM to Source interval. Interval time setting from VCOM to
|
||||
// source dat.
|
||||
// 000 0000 000b ~ 11 1111 1111b: 1 Hsync ~ 1023 Hsync, respectively.
|
||||
// (Default: 018h: 25 Hsync)
|
||||
uint8_t cdi_high:2;
|
||||
uint8_t __rs1:2;
|
||||
// DCI[3:0]: Source to VCOM interval. Interval time setting from source
|
||||
// data to VCOM.
|
||||
// 0000b ~ 1111b: 1 Hsync ~ 16 Hsync, respectively. (Default: 011b: 4
|
||||
// Hsync)
|
||||
uint8_t dci:4;
|
||||
};
|
||||
|
||||
uint8_t cdi_low;
|
||||
} vcom_data_int_settings_t;
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
uint8_t byte0;
|
||||
uint8_t __rs0:2;
|
||||
// HRES[7:2]: Horizontal display resolution.
|
||||
// 00000b ~ 11111b: 4 ~ 256 lines
|
||||
uint8_t hres:6;
|
||||
};
|
||||
|
||||
union {
|
||||
uint8_t byte1;
|
||||
// VRES[9:0]: Vertical display resolution
|
||||
// 0000000000b ~ 1111111111b: 1 ~ 1024 lines
|
||||
uint8_t vres_high:2;
|
||||
uint8_t __rs1:6;
|
||||
};
|
||||
|
||||
uint8_t vres_low;
|
||||
} resolution_settings_t;
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
uint8_t byte0;
|
||||
// G1~4NUM[3:0]: Channel Number used for Gate Group 1~4. For example:
|
||||
// 2: GGx[2:0] ON
|
||||
// 15: GGx[15:0] ON
|
||||
uint8_t g1num:4;
|
||||
uint8_t __rs0:1;
|
||||
// G1~4UD: Gate Group 1~4 Up/Down Selection
|
||||
// 0: Down scan within Gate Group
|
||||
// 1: Up scan within Gate Group (default)
|
||||
uint8_t g1ud:1;
|
||||
// G1~4BS: Gate Group 1~4 Block/Select Selection
|
||||
// 0: Gate Select
|
||||
// 1: Gate Block
|
||||
uint8_t g1bs:1;
|
||||
// G1~4EN: Gate Group 1~4 Enable
|
||||
// 0: Disable
|
||||
// 1: Enable
|
||||
uint8_t g1en:1;
|
||||
};
|
||||
|
||||
union {
|
||||
uint8_t byte1;
|
||||
uint8_t g2num:4;
|
||||
uint8_t __rs1:1;
|
||||
uint8_t g2ud:1;
|
||||
uint8_t g2bs:1;
|
||||
uint8_t g2en:1;
|
||||
};
|
||||
|
||||
union {
|
||||
uint8_t byte2;
|
||||
uint8_t g3num:4;
|
||||
uint8_t __rs2:1;
|
||||
uint8_t g3ud:1;
|
||||
uint8_t g3bs:1;
|
||||
uint8_t g3en:1;
|
||||
};
|
||||
|
||||
union {
|
||||
uint8_t byte3;
|
||||
uint8_t g4num:4;
|
||||
uint8_t __rs3:1;
|
||||
uint8_t g4ud:1;
|
||||
uint8_t g4bs:1;
|
||||
uint8_t g4en:1;
|
||||
};
|
||||
|
||||
union {
|
||||
uint8_t byte4;
|
||||
// GSFB: Gate Select Forward/Backward
|
||||
// 0: Gate select backward
|
||||
// 1: Gate select forward
|
||||
uint8_t gsfb:1;
|
||||
// GBFB: Gate Block Forward/Backward
|
||||
// 0: Gate block backward
|
||||
// 1: Gate block forward
|
||||
uint8_t gbfb:1;
|
||||
uint8_t __rs4:2;
|
||||
// XOPT: XON Option
|
||||
// 0: No all gate on during vertical blanking in XON mode (default)
|
||||
// 1: All gate on during vertical blanking in XON mode
|
||||
uint8_t xopt:1;
|
||||
uint8_t __rs5:3;
|
||||
};
|
||||
} gate_group_settings_t;
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
uint8_t byte0;
|
||||
uint8_t vbds:7;
|
||||
uint8_t __rs0:1;
|
||||
};
|
||||
} border_dc_v_settings_t;
|
||||
|
||||
typedef struct {
|
||||
// Low Power Voltage Selection
|
||||
union {
|
||||
uint8_t byte0;
|
||||
uint8_t lpd_sel:2;
|
||||
uint8_t __rs0:6;
|
||||
};
|
||||
} lpdselect_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t pixel3:2;
|
||||
uint8_t pixel2:2;
|
||||
uint8_t pixel1:2;
|
||||
uint8_t pixel0:2;
|
||||
} data_tranmission_t;
|
||||
|
||||
typedef struct {
|
||||
// X[7:0]: X-axis Start Point. X-axis start point for update display window.
|
||||
// NOTE: The X-axis start point needs to be a multiple of 4.
|
||||
uint8_t x;
|
||||
// Y[9:0]: Y-axis Start Point. Y-axis start point for update display window.
|
||||
union {
|
||||
uint8_t byte1;
|
||||
uint8_t y_high:2;
|
||||
uint8_t __rs0:6;
|
||||
};
|
||||
uint8_t y_low;
|
||||
// W[7:0]: X-axis Window Width. X-axis width for update display window.
|
||||
// NOTE: The width needs to be a multiple of 4.
|
||||
// NOTE: This needs to be set to W - 1.
|
||||
uint8_t w;
|
||||
union {
|
||||
uint8_t byte4;
|
||||
uint8_t l_high:2;
|
||||
uint8_t __rs1:6;
|
||||
};
|
||||
// L[9:0]: Y-axis Window Width. Y-axis width for update display window
|
||||
// NOTE: This needs to be set to L - 1.
|
||||
uint8_t l_low;
|
||||
} data_transmission_window_t;
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
uint8_t byte0;
|
||||
uint8_t mode:2;
|
||||
// DN_EN: Do-nothing function enabled
|
||||
// 0: Data follow VCOM function disable
|
||||
// 1: Data output follows VCOM LUT if new pixel data equal to old pixel
|
||||
// data inside Update Display Area
|
||||
// NOTE: Do-nothing function is always active outside Update Display Area.
|
||||
uint8_t dn_en:1;
|
||||
// RGL_EN: REGAL function control
|
||||
// 0: REGAL function disable
|
||||
// 1: REGAL function enable
|
||||
uint8_t rgl_en:1;
|
||||
// PSCAN: Partial Scan control
|
||||
// 0: Partial Scan disable
|
||||
// 1: Partial Scan enable (Gate Scan within Display Window only)
|
||||
uint8_t pscan:1;
|
||||
uint8_t __rs0:3;
|
||||
};
|
||||
|
||||
//---- new byte
|
||||
// X[7:0]: X-axis Start Point. X-axis start point for update display window.
|
||||
// NOTE: The X-axis start point needs to be a multiple of 4.
|
||||
uint8_t x;
|
||||
// Y[9:0]: Y-axis Start Point. Y-axis start point for update display window.
|
||||
union {
|
||||
uint8_t byte2;
|
||||
uint8_t y_high:2;
|
||||
uint8_t __rs1:6;
|
||||
};
|
||||
//---- new byte
|
||||
uint8_t y_low;
|
||||
// W[7:0]: X-axis Window Width. X-axis width for update display window.
|
||||
// NOTE: The width needs to be a multiple of 4.
|
||||
// NOTE: This needs to be set to W - 1.
|
||||
uint8_t w;
|
||||
// L[9:0]: Y-axis Window Width. Y-axis width for update display window
|
||||
// NOTE: This needs to be set to L - 1.
|
||||
union {
|
||||
uint8_t byte5;
|
||||
uint8_t l_high:2;
|
||||
uint8_t __rs2:6;
|
||||
};
|
||||
uint8_t l_low;
|
||||
} display_refresh_t;
|
||||
|
||||
enum {
|
||||
PanelSetting = 0x00,
|
||||
PowerSetting = 0x01,
|
||||
PowerOff = 0x02,
|
||||
PowerOffSequenceSetting = 0x03,
|
||||
PowerOn = 0x04,
|
||||
BoosterSoftStart = 0x06,
|
||||
DeepSleep = 0x07,
|
||||
DisplayRefresh = 0x12,
|
||||
DataStartTransmission2 = 0x13,
|
||||
DataStartTransmissionWindow = 0x14,
|
||||
KwgVcomLutRegister = 0x20,
|
||||
KwgLutRegister = 0x22,
|
||||
FtLutRegister = 0x26,
|
||||
PllControl = 0x30,
|
||||
TemperatureSensor = 0x40,
|
||||
TemperatureSensorEnable = 0x41,
|
||||
TemperatureSensorWrite = 0x42,
|
||||
TemperatureSensorRead = 0x43,
|
||||
VcomAndDataIntervalSetting = 0x50,
|
||||
LowPowerDetection = 0x51,
|
||||
ResolutionSetting = 0x61,
|
||||
GateGroupSetting = 0x62,
|
||||
GateBlockSetting = 0x63,
|
||||
GateSelectSetting = 0x64,
|
||||
Revision = 0x70,
|
||||
GetStatus = 0x71,
|
||||
AutoMeasureVcom = 0x80,
|
||||
VcomValue = 0x81,
|
||||
VcomDcSetting = 0x82,
|
||||
BorderDcVoltageSetting = 0x84,
|
||||
LpdSelect = 0xE4,
|
||||
};
|
||||
|
||||
|
||||
enum booster_soft_start_min_off {
|
||||
soft_start_min_off_0p27us = 0b000,
|
||||
soft_start_min_off_0p34us = 0b001,
|
||||
soft_start_min_off_0p40us = 0b010,
|
||||
soft_start_min_off_0p50us = 0b011,
|
||||
soft_start_min_off_0p80us = 0b100,
|
||||
soft_start_min_off_1p54us = 0b101,
|
||||
soft_start_min_off_3p34us = 0b110,
|
||||
soft_start_min_off_6p58us = 0b111,
|
||||
};
|
||||
|
||||
enum drive_strength {
|
||||
drive_strength_1 = 0b000,
|
||||
drive_strength_2 = 0b001,
|
||||
drive_strength_3 = 0b010,
|
||||
drive_strength_4 = 0b011,
|
||||
drive_strength_5 = 0b100,
|
||||
drive_strength_6 = 0b101,
|
||||
drive_strength_7 = 0b110,
|
||||
drive_strength_8 = 0b111, // (strongest)
|
||||
};
|
||||
|
||||
enum soft_start_period {
|
||||
soft_start_period_10ms = 0b00,
|
||||
soft_start_period_20ms = 0b01,
|
||||
soft_start_period_30ms = 0b10,
|
||||
soft_start_period_40ms = 0b11,
|
||||
};
|
||||
|
||||
enum lpd_select_lpdsel {
|
||||
LPDSEL_2p2v = 0b00,
|
||||
LPDSEL_2p3v = 0b01,
|
||||
LPDSEL_2p4v = 0b10,
|
||||
LPDSEL_2p5v = 0b11, // (default)
|
||||
};
|
||||
|
||||
#define PHYSICAL_WIDTH 240
|
||||
#define PHYSICAL_HEIGHT 240
|
||||
#define EINK_WHITE 0xFF
|
||||
#define EINK_BLACK 0x00
|
||||
|
||||
static bool poll_gpio(uint32_t gpio, bool desired, uint8_t timeout)
|
||||
{
|
||||
lk_time_t now = current_time();
|
||||
uint32_t current;
|
||||
|
||||
while ((current = gpio_get(gpio)) != desired) {
|
||||
if (current_time() - now > timeout) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (current == desired);
|
||||
}
|
||||
|
||||
/* The display pulls the BUSY line low while BUSY and releases it when done */
|
||||
static bool check_busy(void) {
|
||||
return poll_gpio(GPIO_DISP_BUSY, 1, 100);
|
||||
}
|
||||
|
||||
static inline void assert_reset(void) {
|
||||
gpio_set(GPIO_DISP_RST, 0);
|
||||
}
|
||||
|
||||
static inline void release_reset(void) {
|
||||
gpio_set(GPIO_DISP_RST, 1);
|
||||
}
|
||||
|
||||
static inline void set_data_command_mode(void) {
|
||||
gpio_set(GPIO_DISP_DC, 0);
|
||||
}
|
||||
|
||||
static inline void set_data_parameter_mode(void) {
|
||||
gpio_set(GPIO_DISP_DC, 1);
|
||||
}
|
||||
|
||||
void write_cmd(uint8_t cmd) {
|
||||
uint8_t cmd_buf[1];
|
||||
|
||||
cmd_buf[0] = cmd;
|
||||
set_data_command_mode();
|
||||
#if 0
|
||||
gpio_set(GPIO_DISP_CS, 0);
|
||||
HAL_SPI_Transmit(&SpiHandle, cmd_buf, sizeof(cmd_buf), HAL_MAX_DELAY);
|
||||
gpio_set(GPIO_DISP_CS, 1);
|
||||
#else
|
||||
spi_write(&SpiHandle, cmd_buf, sizeof(cmd_buf), GPIO_DISP_CS);
|
||||
#endif
|
||||
}
|
||||
|
||||
void write_data(uint8_t *buf, size_t len) {
|
||||
set_data_parameter_mode();
|
||||
//enter_critical_section;
|
||||
#if 0
|
||||
gpio_set(GPIO_DISP_CS, 0);
|
||||
HAL_SPI_Transmit(&SpiHandle, buf, len, HAL_MAX_DELAY);
|
||||
gpio_set(GPIO_DISP_CS, 1);
|
||||
#else
|
||||
//spin_lock_irqsave(&lock, state);
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
spi_write(&SpiHandle, buf + i, 1, GPIO_DISP_CS);
|
||||
}
|
||||
//spin_unlock_irqrestore(&lock, state);
|
||||
#endif
|
||||
//exit_critical_section;
|
||||
}
|
||||
|
||||
void write_burst_data(uint8_t *buf, size_t len) {
|
||||
set_data_parameter_mode();
|
||||
//enter_critical_section;
|
||||
#if 0
|
||||
gpio_set(GPIO_DISP_CS, 0);
|
||||
HAL_SPI_Transmit(&SpiHandle, buf, len, HAL_MAX_DELAY);
|
||||
gpio_set(GPIO_DISP_CS, 1);
|
||||
#else
|
||||
int chunk = 256;
|
||||
spin_lock_irqsave(&lock, state);
|
||||
gpio_set(GPIO_DISP_CS, 0);
|
||||
for (size_t off = 0; off < len; off += chunk) {
|
||||
spi_write(&SpiHandle, buf + off, chunk, 0);
|
||||
}
|
||||
gpio_set(GPIO_DISP_CS, 1);
|
||||
spin_unlock_irqrestore(&lock, state);
|
||||
#endif
|
||||
//exit_critical_section;
|
||||
}
|
||||
|
||||
status_t read_data(uint8_t *buf, size_t len) {
|
||||
return spi_read(&SpiHandle, buf, len, GPIO_DISP_CS);
|
||||
}
|
||||
|
||||
status_t get_status(et011tt2_status_t *status) {
|
||||
status_t err;
|
||||
|
||||
if (status == NULL) {
|
||||
return ERR_INVALID_ARGS;
|
||||
}
|
||||
|
||||
write_cmd(GetStatus);
|
||||
err = read_data((uint8_t *) status, sizeof(et011tt2_status_t));
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
status_t eink_init(void) {
|
||||
TRACE_ENTRY;
|
||||
status_t err = NO_ERROR;
|
||||
spin_lock_init(&lock);
|
||||
|
||||
if (!spi_inited) {
|
||||
SpiHandle.Instance = SPI2;
|
||||
SpiHandle.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16;
|
||||
SpiHandle.Init.Direction = SPI_DIRECTION_1LINE;
|
||||
SpiHandle.Init.CLKPhase = SPI_PHASE_1EDGE;
|
||||
SpiHandle.Init.CLKPolarity = SPI_POLARITY_LOW;
|
||||
SpiHandle.Init.DataSize = SPI_DATASIZE_8BIT;
|
||||
SpiHandle.Init.FirstBit = SPI_FIRSTBIT_MSB;
|
||||
SpiHandle.Init.TIMode = SPI_TIMODE_DISABLE;
|
||||
SpiHandle.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
|
||||
SpiHandle.Init.CRCPolynomial = 0;
|
||||
SpiHandle.Init.NSS = SPI_NSS_SOFT;
|
||||
SpiHandle.Init.Mode = SPI_MODE_MASTER;
|
||||
|
||||
err = spi_init(&SpiHandle);
|
||||
if (err != HAL_OK) {
|
||||
printf("Failed to init spi\n");
|
||||
}
|
||||
|
||||
spi_inited = true;
|
||||
}
|
||||
|
||||
panel_setting_t panel = {
|
||||
.byte0 = 0x0F, .byte1 = 0x06,
|
||||
};
|
||||
|
||||
panel.reg_en = 1;
|
||||
|
||||
pwr_settings_t pwr = {
|
||||
.byte0 = 0x03, .byte1 = 0x00, .byte2 = 0x26, .byte3 = 0x26, .byte4 = 0x03,
|
||||
};
|
||||
|
||||
pwr.vsh_lvl = 0x1C; // +8V
|
||||
pwr.vsl_lvl = 0x1C; // -8V
|
||||
pwr.vshr_lvl = 0x00; // +2.4V
|
||||
|
||||
booster_settings_t booster = {
|
||||
.byte0 = 0x1F, .byte1 = 0x1E, .byte2 = 0x25,
|
||||
|
||||
};
|
||||
|
||||
booster.btpha_min_off = soft_start_min_off_3p34us;
|
||||
booster.btpha_drive_strength = drive_strength_8;
|
||||
booster.btpha_soft_start = soft_start_period_10ms;
|
||||
booster.btphb_min_off = soft_start_min_off_3p34us;
|
||||
booster.btphb_drive_strength = drive_strength_8;
|
||||
booster.btphb_soft_start = soft_start_period_10ms;
|
||||
booster.btphc_min_off = soft_start_min_off_3p34us;
|
||||
booster.btphc_drive_strength = drive_strength_8;
|
||||
|
||||
vcom_data_int_settings_t vdi = {
|
||||
.byte0 = 0x31, .byte1 = 0x30, .cdi_low = 0x18,
|
||||
};
|
||||
|
||||
vdi.bdd = 0x00; // PC30
|
||||
vdi.dci = 0x02; // 3 Hsync
|
||||
vdi.cdi_low = 0x10; // 17 Hsync
|
||||
|
||||
resolution_settings_t rs = {
|
||||
.byte0 = 0x03, .byte1 = 0x00, .vres_low = 0xEF,
|
||||
};
|
||||
|
||||
rs.hres = (PHYSICAL_WIDTH - 1) >> 2;
|
||||
rs.vres_low = PHYSICAL_HEIGHT - 1;
|
||||
|
||||
border_dc_v_settings_t bdvs = {
|
||||
.byte0 = 0x00,
|
||||
};
|
||||
|
||||
bdvs.vbds = 0x4e; // -4.0V
|
||||
|
||||
gate_group_settings_t ggs = {
|
||||
.byte0 = 0xAF, .byte1 = 0xAF, .byte2 = 0xEF, .byte3 = 0xEF, .byte4 = 0x03,
|
||||
};
|
||||
|
||||
ggs.g1num = 0x09; // GG1[9:0] ON
|
||||
ggs.g1ud = 0; // GG1[9] -> GG1[0]
|
||||
ggs.g2num = 0x09; // GG2[9:0] ON
|
||||
ggs.g2ud = 0; // GG2[9] -> GG2[0]
|
||||
ggs.g3num = 0x0B; // GG3[11:0] ON
|
||||
ggs.g3ud = 0; // GG3[11] -> GG3[0]
|
||||
ggs.g3bs = 1; // Gate block
|
||||
ggs.g4num = 0x0B; // GG4[11:0] ON
|
||||
ggs.g4ud = 0; // GG4[11] -> GG4[0]
|
||||
ggs.g4bs = 1; // Gate block
|
||||
|
||||
lpdselect_t lpds = {
|
||||
.byte0 = 0x03,
|
||||
|
||||
};
|
||||
|
||||
lpds.lpd_sel = LPDSEL_2p4v;
|
||||
|
||||
display_refresh_t dr = {
|
||||
.byte0 = 0x0, .x = 0x0, .byte2 = 0x0, .y_low = 0x0, .w = 0xFF, .byte5 = 0x01, .l_low = 0xFF,
|
||||
|
||||
};
|
||||
|
||||
dr.x = 0;
|
||||
dr.y_low = 0;
|
||||
dr.w = 240-1;
|
||||
dr.l_high = 0;
|
||||
dr.l_low = 240-1;
|
||||
|
||||
data_transmission_window_t dtw = {
|
||||
.x = 0x0, .byte1 = 0x0, .y_low = 0x0, .w = 0x7F, .byte4 = 0x03, .l_low = 0xFF,
|
||||
};
|
||||
|
||||
dtw.x = 0;
|
||||
dtw.y_low = 0;
|
||||
dtw.w = 240-1;
|
||||
dtw.l_high = 0;
|
||||
dtw.l_low = 240-1;
|
||||
|
||||
set_data_command_mode();
|
||||
|
||||
// VDD (wired straight to 3v3)
|
||||
spin(2000); // Delay 2 ms
|
||||
assert_reset(); // RST_LOW
|
||||
spin(30); // Delay 30 us
|
||||
release_reset(); // RST_HIGH
|
||||
|
||||
if (!check_busy()) {
|
||||
printf("Device is still busy after initial reset!\n");
|
||||
return ERR_GENERIC;
|
||||
}
|
||||
|
||||
// Configure power settings
|
||||
write_cmd(PowerSetting);
|
||||
write_data((uint8_t *)&pwr, sizeof(pwr));
|
||||
|
||||
// Power on display
|
||||
write_cmd(PowerOn);
|
||||
|
||||
// Configure panel settings
|
||||
write_cmd(PanelSetting);
|
||||
write_data((uint8_t *)&panel, sizeof(panel));
|
||||
|
||||
// Configure Boost
|
||||
write_cmd(BoosterSoftStart);
|
||||
write_data((uint8_t *)&booster, sizeof(booster));
|
||||
|
||||
// Initialize -> Check_Busy
|
||||
write_cmd(VcomAndDataIntervalSetting);
|
||||
write_data((uint8_t *)&vdi, sizeof(vdi));
|
||||
|
||||
write_cmd(ResolutionSetting);
|
||||
write_data((uint8_t *)&rs, sizeof(rs));
|
||||
|
||||
write_cmd(GateGroupSetting);
|
||||
write_data((uint8_t *)&ggs, sizeof(ggs));
|
||||
|
||||
write_cmd(BorderDcVoltageSetting);
|
||||
write_data((uint8_t *)&bdvs, sizeof(bdvs));
|
||||
|
||||
write_cmd(LpdSelect);
|
||||
write_data((uint8_t *)&lpds, sizeof(lpds));
|
||||
|
||||
write_cmd(FtLutRegister);
|
||||
write_data(lut_ft, sizeof(lut_ft));
|
||||
|
||||
write_cmd(KwgVcomLutRegister);
|
||||
write_data(lut_kwg_vcom, sizeof(lut_kwg_vcom));
|
||||
|
||||
write_cmd(KwgLutRegister);
|
||||
write_data(lut_kwg, sizeof(lut_kwg));
|
||||
|
||||
if (!check_busy()) {
|
||||
printf("Device is still busy after Power On and configuration\n");
|
||||
return ERR_GENERIC;
|
||||
}
|
||||
|
||||
/* Quick buffer to toss at it */
|
||||
#define fbsize (240 * 240 / 4)
|
||||
uint8_t *buf = malloc(fbsize);
|
||||
if (!buf) {
|
||||
printf("Couldn't allocate framebuffer\n");
|
||||
return ERR_GENERIC;
|
||||
}
|
||||
memset(buf, 0b00001111, fbsize);
|
||||
|
||||
// DTMW
|
||||
write_cmd(DataStartTransmissionWindow);
|
||||
write_data((uint8_t *) &dtw, sizeof(dtw));
|
||||
|
||||
// DTM2
|
||||
write_cmd(DataStartTransmission2);
|
||||
write_data(buf, fbsize);
|
||||
|
||||
// DRF
|
||||
write_cmd(DisplayRefresh);
|
||||
write_data((uint8_t *)&dr, sizeof(dr));
|
||||
|
||||
// Check_Busy
|
||||
if (!check_busy()) {
|
||||
printf("Device is still busy after Display Refresh!\n");
|
||||
return ERR_GENERIC;
|
||||
}
|
||||
|
||||
// POF
|
||||
write_cmd(PowerOff);
|
||||
|
||||
// Check_Busy
|
||||
if (!check_busy()) {
|
||||
printf("Device is still busy after Power Off!\n");
|
||||
return ERR_GENERIC;
|
||||
}
|
||||
|
||||
// DSLP
|
||||
uint8_t sleepbuf = 0b10100101;
|
||||
write_cmd(DeepSleep);
|
||||
write_data(&sleepbuf, sizeof(sleepbuf));
|
||||
|
||||
err:
|
||||
TRACE_EXIT;
|
||||
return err;
|
||||
}
|
||||
|
||||
static int cmd_eink(int argc, const cmd_args *argv)
|
||||
{
|
||||
return eink_init();
|
||||
}
|
||||
|
||||
STATIC_COMMAND_START
|
||||
STATIC_COMMAND("eink", "eink commands", &cmd_eink)
|
||||
STATIC_COMMAND_END(eink);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -78,16 +78,26 @@
|
||||
__HAL_RCC_GPIOK_CLK_ENABLE(); \
|
||||
__HAL_RCC_GPIOF_CLK_ENABLE()
|
||||
|
||||
#define GPIO_NRF_RST GPIO(GPIO_PORT_A, 13)
|
||||
#define GPIO_NRF_SWDIO GPIO(GPIO_PORT_A, 13)
|
||||
#define GPIO_NRF_SWCLK GPIO(GPIO_PORT_A, 14)
|
||||
#define GPIO_NRF_CS GPIO(GPIO_PORT_K, 0)
|
||||
#define GPIO_NRF_INT GPIO(GPIO_PORT_K, 1)
|
||||
#define GPIO_GYRO_nCS GPIO(GPIO_PORT_K, 4)
|
||||
#define GPIO_GYRO_INT GPIO(GPIO_PORT_K, 5)
|
||||
#define GPIO_ACC_nCS GPIO(GPIO_PORT_K, 2)
|
||||
#define GPIO_ACC_INT GPIO(GPIO_PORT_K, 3)
|
||||
#define GPIO_SPI2_SCK GPIO(GPIO_PORT_D, 3)
|
||||
#define GPIO_SPI2_MISO GPIO(GPIO_PORT_I, 2)
|
||||
#define GPIO_SPI2_MOSI GPIO(GPIO_PORT_B, 15)
|
||||
#define GPIO_SPI5_SCK GPIO(GPIO_PORT_F, 7)
|
||||
#define GPIO_SPI5_MISO GPIO(GPIO_PORT_F, 8)
|
||||
#define GPIO_SPI5_MOSI GPIO(GPIO_PORT_F, 9)
|
||||
|
||||
|
||||
#define GPIO_DISP_CS GPIO(GPIO_PORT_B, 12)
|
||||
#define GPIO_DISP_SCK GPIO(GPIO_PORT_D, 3)
|
||||
#define GPIO_DISP_MOSI GPIO(GPIO_PORT_B, 15)
|
||||
#define GPIO_DISP_BUSY GPIO(GPIO_PORT_I, 4)
|
||||
#define GPIO_DISP_DC GPIO(GPIO_PORT_I, 5)
|
||||
#define GPIO_DISP_RST GPIO(GPIO_PORT_K, 6)
|
||||
|
||||
#endif
|
||||
|
||||
@@ -128,13 +128,13 @@ void target_init(void)
|
||||
{
|
||||
stm32_debug_init();
|
||||
|
||||
qspi_flash_init(N25Q128A_FLASH_SIZE);
|
||||
//qspi_flash_init(N25Q128A_FLASH_SIZE);
|
||||
|
||||
#if ENABLE_LCD
|
||||
#if 0 //ENABLE_LCD
|
||||
memory_lcd_init();
|
||||
#endif
|
||||
|
||||
#if WITH_LIB_MINIP
|
||||
#if 0 //WITH_LIB_MINIP
|
||||
uint8_t mac_addr[6];
|
||||
gen_random_mac_address(mac_addr);
|
||||
eth_init(mac_addr, PHY_KSZ8721);
|
||||
@@ -149,7 +149,7 @@ void target_init(void)
|
||||
minip_init(stm32_eth_send_minip_pkt, NULL, ip_addr, ip_mask, ip_gateway);
|
||||
#endif
|
||||
|
||||
#if WITH_LIB_FS_SPIFS
|
||||
#if 0 //WITH_LIB_FS_SPIFS
|
||||
status_t mount_success = fs_mount(DEAULT_SPIFS_MOUNT_POINT,
|
||||
DEAULT_SPIFS_NAME, SPIFS_TARGET_DEVICE);
|
||||
if (mount_success != NO_ERROR) {
|
||||
@@ -162,9 +162,9 @@ void target_init(void)
|
||||
#endif
|
||||
|
||||
// start usb
|
||||
target_usb_setup();
|
||||
//target_usb_setup();
|
||||
|
||||
#if ENABLE_SENSORBUS
|
||||
#if 0 //ENABLE_SENSORBUS
|
||||
sensor_bus_init();
|
||||
#endif
|
||||
}
|
||||
@@ -173,41 +173,72 @@ void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi)
|
||||
{
|
||||
GPIO_InitTypeDef GPIO_InitStruct;
|
||||
if (hspi->Instance == SPI2) {
|
||||
/*##-1- Enable peripherals and GPIO Clocks #################################*/
|
||||
/* Enable GPIO TX/RX clock */
|
||||
__HAL_RCC_GPIOD_CLK_ENABLE();
|
||||
__HAL_RCC_GPIOK_CLK_ENABLE();
|
||||
/* SPI2
|
||||
* PB15 MOSI
|
||||
* PD3 SCK
|
||||
* PB12 CS (soft)
|
||||
*/
|
||||
printf("Configuring SPI2.\n");
|
||||
__HAL_RCC_GPIOB_CLK_ENABLE();
|
||||
/* Enable SPI clock */
|
||||
__HAL_RCC_GPIOD_CLK_ENABLE();
|
||||
__HAL_RCC_GPIOI_CLK_ENABLE();
|
||||
__HAL_RCC_GPIOK_CLK_ENABLE();
|
||||
__HAL_RCC_SPI2_CLK_ENABLE();
|
||||
|
||||
/*##-2- Configure peripheral GPIO ##########################################*/
|
||||
/* SPI SCK GPIO pin configuration */
|
||||
GPIO_InitStruct.Pin = GPIO_PIN_3;
|
||||
/* Common SPI2 AF config */
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
|
||||
GPIO_InitStruct.Pull = GPIO_PULLDOWN;
|
||||
GPIO_InitStruct.Pull = 0x2; // GPIO_PULLDOWN
|
||||
GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
|
||||
GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
|
||||
|
||||
/* SPI2 MOSI GPIO pin configuration */
|
||||
GPIO_InitStruct.Pin = GPIO_PIN_15;
|
||||
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
|
||||
|
||||
/* SPI2 SCK GPIO pin configuration */
|
||||
GPIO_InitStruct.Pin = GPIO_PIN_3;
|
||||
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
|
||||
|
||||
/* SPI MOSI GPIO pin configuration */
|
||||
GPIO_InitStruct.Pin = GPIO_PIN_15;
|
||||
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
|
||||
|
||||
/* SPI2 CS GPIO pin configuration (general output GPIO) */
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
|
||||
/* LCD_ON Pin configuration */
|
||||
GPIO_InitStruct.Pin = GPIO_PIN_6;
|
||||
HAL_GPIO_Init(GPIOK, &GPIO_InitStruct);
|
||||
|
||||
/* LCD_CS Pin configuration */
|
||||
GPIO_InitStruct.Pin = GPIO_PIN_12;
|
||||
GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
|
||||
GPIO_InitStruct.Pin = GPIO_PIN_12;
|
||||
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
|
||||
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_SET);
|
||||
|
||||
/* DISP_DC pin configuration (general output GPIO) */
|
||||
GPIO_InitStruct.Pin = GPIO_PIN_5;
|
||||
HAL_GPIO_Init(GPIOI, &GPIO_InitStruct);
|
||||
HAL_GPIO_WritePin(GPIOI, GPIO_PIN_5, GPIO_PIN_RESET);
|
||||
|
||||
/* DISP_RESET pin configuration (general output GPIO) */
|
||||
GPIO_InitStruct.Pin = GPIO_PIN_6;
|
||||
HAL_GPIO_Init(GPIOK, &GPIO_InitStruct);
|
||||
HAL_GPIO_WritePin(GPIOK, GPIO_PIN_6, GPIO_PIN_RESET);
|
||||
|
||||
/* DISP_BUSY GPIO pin configuration (general output GPIO) */
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
|
||||
GPIO_InitStruct.Pin = GPIO_PIN_4;
|
||||
HAL_GPIO_Init(GPIOI, &GPIO_InitStruct);
|
||||
|
||||
/*##-3- Configure the NVIC for SPI #########################################*/
|
||||
/* NVIC for SPI */
|
||||
HAL_NVIC_EnableIRQ(SPI2_IRQn);
|
||||
} else if (hspi->Instance == SPI5) {
|
||||
/* SPI5
|
||||
* PF6 SPI5_NSS
|
||||
* PF7 SPI5_SCK
|
||||
* PF8 SPI5_MISO
|
||||
* PF9 SPI5_MOSI
|
||||
*/
|
||||
__HAL_RCC_GPIOF_CLK_ENABLE();
|
||||
__HAL_RCC_SPI5_CLK_ENABLE();
|
||||
gpio_config(GPIO_SPI5_SCK, GPIO_STM32_AF | GPIO_STM32_AFn(GPIO_AF5_SPI5) | GPIO_PULLUP);
|
||||
gpio_config(GPIO_SPI5_MISO, GPIO_STM32_AF | GPIO_STM32_AFn(GPIO_AF5_SPI5) | GPIO_PULLUP);
|
||||
gpio_config(GPIO_SPI5_MOSI, GPIO_STM32_AF | GPIO_STM32_AFn(GPIO_AF5_SPI5) | GPIO_PULLUP);
|
||||
HAL_NVIC_EnableIRQ(SPI5_IRQn);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ PLATFORM := stm32f7xx
|
||||
SDRAM_SIZE := 0x00800000
|
||||
SDRAM_BASE := 0xc0000000
|
||||
|
||||
DISPLAY_PANEL_TYPE ?= LS013B7DH06
|
||||
GLOBAL_DEFINES += \
|
||||
ENABLE_UART3=1 \
|
||||
ENABLE_SDRAM=1 \
|
||||
@@ -28,6 +29,7 @@ GLOBAL_INCLUDES += $(LOCAL_DIR)/include
|
||||
|
||||
MODULE_SRCS += \
|
||||
$(LOCAL_DIR)/init.c \
|
||||
$(LOCAL_DIR)/display/eink.c \
|
||||
$(LOCAL_DIR)/sensor_bus.c \
|
||||
$(LOCAL_DIR)/usb.c \
|
||||
|
||||
@@ -41,7 +43,7 @@ MODULE_SRCS += \
|
||||
$(LOCAL_DIR)/memory_lcd.c
|
||||
|
||||
GLOBAL_DEFINES += \
|
||||
ENABLE_LCD=1
|
||||
ENABLE_LCD=0
|
||||
|
||||
endif
|
||||
|
||||
|
||||
@@ -23,12 +23,12 @@
|
||||
#include <err.h>
|
||||
#include <kernel/mutex.h>
|
||||
#include <platform/gpio.h>
|
||||
#include <platform/spi.h>
|
||||
#include <target/gpioconfig.h>
|
||||
#include <target/bmi055.h>
|
||||
#include <target/sensor_bus.h>
|
||||
#include <dev/accelerometer.h>
|
||||
|
||||
static mutex_t sensorbus_mutex;
|
||||
static SPI_HandleTypeDef spi_handle;
|
||||
|
||||
static uint8_t tx_buff[16];
|
||||
@@ -49,19 +49,7 @@ status_t acc_read_xyz(position_vector_t *pos_vector_p)
|
||||
|
||||
status_t acc_flush(uint8_t *tbuff, uint8_t *rbuff, uint8_t numbytes)
|
||||
{
|
||||
status_t ret_status;
|
||||
|
||||
mutex_acquire(&sensorbus_mutex);
|
||||
|
||||
gpio_set(GPIO_ACC_nCS,GPIO_PIN_RESET);
|
||||
|
||||
ret_status = HAL_SPI_TransmitReceive(&spi_handle, tbuff, rbuff, numbytes, 5000);
|
||||
|
||||
gpio_set(GPIO_ACC_nCS,GPIO_PIN_SET);
|
||||
|
||||
mutex_release(&sensorbus_mutex);
|
||||
|
||||
return ret_status;
|
||||
return spi_transaction(&spi_handle, tbuff, rbuff, numbytes, GPIO_ACC_nCS);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -71,11 +59,6 @@ status_t acc_flush(uint8_t *tbuff, uint8_t *rbuff, uint8_t numbytes)
|
||||
status_t sensor_bus_init_early(void)
|
||||
{
|
||||
__HAL_SENSOR_BUS_GPIO_CLK_ENABLE();
|
||||
__HAL_RCC_SPI5_CLK_ENABLE();
|
||||
|
||||
gpio_config(GPIO_SPI5_SCK, GPIO_STM32_AF | GPIO_STM32_AFn(GPIO_AF5_SPI5) | GPIO_PULLUP);
|
||||
gpio_config(GPIO_SPI5_MISO, GPIO_STM32_AF | GPIO_STM32_AFn(GPIO_AF5_SPI5) | GPIO_PULLUP);
|
||||
gpio_config(GPIO_SPI5_MOSI, GPIO_STM32_AF | GPIO_STM32_AFn(GPIO_AF5_SPI5) | GPIO_PULLUP);
|
||||
|
||||
gpio_config(GPIO_NRF_CS, GPIO_OUTPUT );
|
||||
gpio_config(GPIO_NRF_INT, GPIO_INPUT | GPIO_PULLUP);
|
||||
@@ -109,11 +92,8 @@ status_t sensor_bus_init_early(void)
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void sensor_bus_init(void)
|
||||
{
|
||||
mutex_init(&sensorbus_mutex);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ GLOBAL_DEFINES += \
|
||||
MODULE_SRCS += \
|
||||
$(LOCAL_DIR)/init.c \
|
||||
$(LOCAL_DIR)/lcd.c \
|
||||
$(LOCAL_DIR)/spi.c \
|
||||
$(LOCAL_DIR)/usb.c
|
||||
|
||||
MODULE_DEPS += \
|
||||
|
||||
Reference in New Issue
Block a user