Skip to content

Instantly share code, notes, and snippets.

@GregAC
Created April 27, 2024 22:10
Show Gist options
  • Save GregAC/b4bdd5ec5d325f96cef2764c0d47b001 to your computer and use it in GitHub Desktop.
Save GregAC/b4bdd5ec5d325f96cef2764c0d47b001 to your computer and use it in GitHub Desktop.
Sonata SPI flash example
#include <stdint.h>
#define DEV_WRITE(addr, val) (*((volatile uint32_t *)(addr)) = val)
#define DEV_READ(addr) (*((volatile uint32_t *)(addr)))
#define SPI_BASE 0x83000000
#define SPI_CFG 0xc
#define SPI_CONTROL 0x10
#define SPI_STATUS 0x14
#define SPI_START 0x18
#define SPI_RX_FIFO 0x1c
#define SPI_TX_FIFO 0x20
#define UART_BASE 0x81000000
#define UART_CTRL 0x10
#define UART_WDATA 0x1c
#define UART_FIFO_STATUS 0x24
#define GPIO_BASE 0x80000000
// 2 mbaud
#define UART_NCO 41943
void uart_init() {
// Set NCO + TX enable
DEV_WRITE(UART_BASE + UART_CTRL, (UART_NCO) << 16 | 0x1);
}
void uart_write(char* str) {
uint32_t tx_avail = 32 - (DEV_READ(UART_BASE + UART_FIFO_STATUS) & 0xff);
while (*str) {
if (tx_avail == 0) {
while (tx_avail < 30) {
tx_avail = 32 - (DEV_READ(UART_BASE + UART_FIFO_STATUS) & 0xff);
}
}
DEV_WRITE(UART_BASE + UART_WDATA, (uint32_t)*str);
++str;
--tx_avail;
}
}
void uart_hex_out(uint32_t n) {
char str_buf[9];
for (int i = 0;i < 8;++i) {
if ((n & 0xf) < 10) {
str_buf[7 - i] = (n & 0xf) + '0';
} else {
str_buf[7 - i] = (n & 0xf) + 'a' - 10;
}
n >>= 4;
}
str_buf[8] = 0;
uart_write(str_buf);
}
void uart_hex_out8b(uint8_t n) {
char str_buf[3];
for (int i = 0;i < 2;++i) {
if ((n & 0xf) < 10) {
str_buf[1 - i] = (n & 0xf) + '0';
} else {
str_buf[1 - i] = (n & 0xf) + 'a' - 10;
}
n >>= 4;
}
str_buf[2] = 0;
uart_write(str_buf);
}
void spi_wait_idle() {
while((DEV_READ(SPI_BASE + SPI_STATUS) & 0x40000) == 0);
}
void spi_tx(uint8_t* data, uint32_t len) {
spi_wait_idle();
// TX_ENABLE
DEV_WRITE(SPI_BASE + SPI_CONTROL, 0x4);
DEV_WRITE(SPI_BASE + SPI_START, len);
uint32_t tx_avail = 0;
for (int i = 0;i < len; ++i) {
if (tx_avail == 0) {
while (tx_avail < 120) {
tx_avail = 128 - (DEV_READ(SPI_BASE + SPI_STATUS) & 0xff);
}
}
DEV_WRITE(SPI_BASE + SPI_TX_FIFO, data[i]);
tx_avail--;
}
}
void spi_rx(uint8_t* data, uint32_t len) {
spi_wait_idle();
// RX_ENABLE
DEV_WRITE(SPI_BASE + SPI_CONTROL, 0x8);
DEV_WRITE(SPI_BASE + SPI_START, len);
for (int i = 0;i < len; ++i) {
while (((DEV_READ(SPI_BASE + SPI_STATUS) >> 8) & 0xff) == 0);
data[i] = (uint8_t)DEV_READ(SPI_BASE + SPI_RX_FIFO);;
}
}
void spi_csn(uint32_t csn) {
DEV_WRITE(GPIO_BASE, (csn & 1) << 12);
}
uint8_t CmdReadJEDECId = 0x9f;
uint8_t CmdWriteEnable = 0x06;
uint8_t CmdSectorErase = 0x20;
uint8_t CmdReadStatusRegister1 = 0x05;
uint8_t CmdPageProgram = 0x02;
uint8_t CmdReadData = 0x03;
void flash_erase_sector(uint32_t sector_idx) {
uint8_t erase_cmd[4] = {CmdSectorErase, (sector_idx >> 16) & 0xff,
(sector_idx >> 8) & 0xff, sector_idx & 0xff};
spi_csn(0);
spi_tx(&CmdWriteEnable, 1);
spi_csn(1);
spi_csn(0);
spi_tx(erase_cmd, 4);
spi_csn(1);
spi_csn(0);
spi_tx(&CmdReadStatusRegister1, 1);
uint8_t status;
do {
spi_rx(&status, 1);
} while ((status & 0x1) == 1);
spi_csn(1);
}
void flash_write_page(uint32_t page_idx, uint8_t* data) {
uint8_t write_cmd[4] = {CmdPageProgram, (page_idx >> 16) & 0xff,
(page_idx >> 8) & 0xff, page_idx & 0xff};
spi_csn(0);
spi_tx(&CmdWriteEnable, 1);
spi_csn(1);
spi_csn(0);
spi_tx(write_cmd, 4);
spi_tx(data, 256);
spi_csn(1);
spi_csn(0);
spi_tx(&CmdReadStatusRegister1, 1);
uint8_t status;
do {
spi_rx(&status, 1);
} while ((status & 0x1) == 1);
spi_csn(1);
}
void flash_read(uint32_t address, uint8_t* data_out, uint32_t len) {
uint8_t read_cmd[4] = {CmdReadData, (address >> 16) & 0xff,
(address >> 8) & 0xff, address & 0xff};
spi_csn(0);
spi_tx(read_cmd, 4);
spi_rx(data_out, len);
spi_csn(1);
}
void spi_test() {
uint8_t jedec_data[3];
spi_csn(0);
spi_tx(&CmdReadJEDECId, 1);
spi_rx(jedec_data, 3);
spi_csn(1);
uart_write("Got JEDEC data ");
uart_hex_out8b(jedec_data[0]);
uart_write(" ");
uart_hex_out8b(jedec_data[1]);
uart_write(" ");
uart_hex_out8b(jedec_data[2]);
uart_write("\r\n");
}
uint8_t write_data[256];
uint8_t read_data[256];
int main(void) {
for (int i = 0;i < 256; ++i) {
write_data[i] = i;
}
spi_csn(1);
uart_init();
uart_write("Hello world\r\n");
spi_test();
flash_erase_sector(0);
flash_write_page(0, write_data);
flash_read(0, read_data, 256);
uart_write("Got first flash read:\r\n");
for (int i = 0;i < 256; ++i) {
uart_hex_out8b(read_data[i]);
uart_write("\r\n");
}
flash_read(128, read_data, 256);
uart_write("Got second flash read:\r\n");
for (int i = 0;i < 256; ++i) {
uart_hex_out8b(read_data[i]);
uart_write("\r\n");
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment