/* https://yogiken.files.wordpress.com/2010/02/c-register-access.pdf */ #include #include #include #include #include #include #include #include "bits.h" struct spi { qm_spi_t id; }; struct gpio_pin { qm_gpio_t port; uint8_t pin; }; struct pcd8544 { struct spi *spi; /* 1 = data, 0 = command */ struct gpio_pin *pin_dc; struct gpio_pin *pin_res; }; void spi_new(struct spi *spi, qm_spi_t id) { clk_periph_enable(CLK_PERIPH_SPI_M0); spi->id = id; qm_pmux_select(QM_PIN_ID_16, QM_PMUX_FN_2); /* SCL */ qm_pmux_select(QM_PIN_ID_17, QM_PMUX_FN_2); /* TXD */ qm_pmux_input_en(QM_PIN_ID_18, true); } void spi_enable(struct spi *spi) { qm_spi_config_t cfg = { .frame_size = QM_SPI_FRAME_SIZE_8_BIT, .transfer_mode = QM_SPI_TMOD_TX_RX, .bus_mode = QM_SPI_BMODE_0, .clk_divider = 2 }; qm_spi_set_config(spi->id, &cfg); } void spi_delete(struct spi const *const spi) { } void spi_exchange(struct spi const *const spi, uint8_t *tx, size_t tx_len, uint8_t *rx, size_t rx_len) { qm_spi_transfer_t transfer = { .tx = tx, .tx_len = tx_len, .rx = rx, .rx_len = rx_len }; qm_spi_transfer(spi->id, &transfer); } void spi_tx(struct spi const *const spi, uint8_t *tx, size_t tx_len) { qm_spi_config_t cfg = { .frame_size = QM_SPI_FRAME_SIZE_8_BIT, .transfer_mode = QM_SPI_TMOD_TX, .bus_mode = QM_SPI_BMODE_0, .clk_divider = 32 /* 8 == 4MHz */ }; qm_spi_set_config(spi->id, &cfg); qm_spi_transfer_t transfer = { .tx = tx, .tx_len = tx_len, .rx = 0, .rx_len = 0 }; qm_spi_transfer(spi->id, &transfer); } void gpio_pin_new(struct gpio_pin *gp, int port, uint8_t pin) { assert(port == 0); gp->port = QM_GPIO_0; gp->pin = pin; qm_gpio_port_config_t cfg = { .direction = (uint32_t) BIT_MASK(pin), .int_en = 0, .int_type = 0, .int_polarity = 0, .int_debounce = 0, .int_bothedge = 0, .callback = NULL }; qm_gpio_set_config(gp->port, &cfg); } void gpio_pin_set(struct gpio_pin *gp) { qm_gpio_set_pin(gp->port, gp->pin); } void gpio_pin_reset(struct gpio_pin *gp) { } uint8_t pcd8544_cmd_function(bool power_down, bool vertical_mode, bool extended_instruction_set) { return (uint8_t) ((power_down & BIT_MASK_1(2)) | (vertical_mode & BIT_MASK_1(1)) | (extended_instruction_set & BIT_MASK_1(0))); } uint8_t pcd8544_cmd_display_function(bool d, bool e) { return (uint8_t) (BIT_MASK_1(3) | (d & BIT_MASK_1(2)) | (e & BIT_MASK_1(0))); } uint8_t pcd8544_cmd_x_address(int address) { return (uint8_t) (BIT_MASK_1(6) | (address & BIT_MASK_3(2, 1, 0))); } uint8_t pcd8544_cmd_y_address(int address) { return (uint8_t) (BIT_MASK_1(7) | (address & BIT_MASK(5, 4, 3, 2, 1, 0))); } void pcd8544_new(struct pcd8544 *pcd8544, struct spi *spi, struct gpio_pin *pin_dc, struct gpio_pin *pin_res) { pcd8544->spi = spi; pcd8544->pin_dc = pin_dc; pcd8544->pin_res = pin_res; } void pcd8544_delete(struct pcd8544 *pcd8544) { } void pcd8544_reset(struct pcd8544 *pcd8544) { gpio_pin_reset(pcd8544->pin_res); clk_sys_udelay(10 * 1000); gpio_pin_set(pcd8544->pin_res); gpio_pin_reset(pcd8544->pin_dc); uint8_t tx[] = { pcd8544_cmd_function(false, false, false), pcd8544_cmd_y_address(0), pcd8544_cmd_x_address(0) }; uint8_t rx[] = { 0, 0, 0 }; spi_exchange(pcd8544->spi, tx, sizeof(tx), rx, sizeof(rx)); gpio_pin_set(pcd8544->pin_dc); } void pcd8544_fun(struct pcd8544 *pcd8544) { uint8_t tx[] = { 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, }; spi_tx(pcd8544->spi, tx, sizeof(tx)); } struct spi spi; struct pcd8544 pcd8544; struct gpio_pin pin_dc, pin_res; int main() { clk_periph_enable(CLK_PERIPH_CLK); spi_new(&spi, QM_SPI_MST_0); spi_enable(&spi); gpio_pin_new(&pin_dc, 0, 3); gpio_pin_new(&pin_res, 0, 4); pcd8544_new(&pcd8544, &spi, &pin_dc, &pin_res); pcd8544_reset(&pcd8544); pcd8544_fun(&pcd8544); pcd8544_delete(&pcd8544); spi_delete(&spi); return 0; }