-
Notifications
You must be signed in to change notification settings - Fork 24
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How to write to flash? #52
Comments
Currently, you should use the bitbang registers (e.g. https://rm.fomu.im/lxspi.html) to send raw SPI commands. An example of how to do this can be found in Foboot. Use Then call |
@xobs |
LiteSPI doesn't have bitbang registers, @xobs code is for For LiteSPI you can use the registers provided by the #!/usr/bin/env python3
import sys
import deps
from litex.tools.litex_client import RemoteClient
c = RemoteClient()
c.open()
PROGRAM_SIZE = 256
ERASE_SIZE = 4096
def transfer_byte(b):
while not (c.regs.spiflash_mmap_master_status.read() & (1 << 0)):
pass
c.regs.spiflash_mmap_master_rxtx.write(b)
while not (c.regs.spiflash_mmap_master_status.read() & (1 << 1)):
pass
return c.regs.spiflash_mmap_master_rxtx.read()
def transfer_cmd(bs):
c.regs.spiflash_mmap_master_phyconfig.write((1 << 16) | (1 << 8) | (8 << 0))
c.regs.spiflash_mmap_master_cs.write(1)
r = [transfer_byte(b) for b in bs]
c.regs.spiflash_mmap_master_cs.write(0)
return bytes(r)
def read_status_register():
return transfer_cmd(b'\x05\x00')[1]
def write_enable():
transfer_cmd(b'\x06')
def page_program(addr, data):
transfer_cmd(b'\x02' + addr.to_bytes(3, 'big') + data)
def sector_erase(addr):
transfer_cmd(b'\x20' + addr.to_bytes(3, 'big'))
def write_stream(addr, stream):
assert addr & (ERASE_SIZE - 1) == 0
while True:
data = stream.read(PROGRAM_SIZE)
if not data:
break
if addr & (ERASE_SIZE - 1) == 0:
write_enable()
sector_erase(addr)
while read_status_register() & 1:
pass
print(f'Erased addr {addr}.')
write_enable()
page_program(addr, data)
while read_status_register() & 1:
pass
print(f'Wrote {len(data)} bytes.')
addr += len(data)
def main():
with open(sys.argv[1], 'rb') as f:
write_stream(0, f)
if __name__ == '__main__':
main() If you want a faster option, I've written a flash writer module that just takes a data and address stream: https://github.com/orbcode/orbtrace/blob/main/orbtrace/flashwriter.py |
@zyp |
FYI - @kgugala |
@navaneeth-cirel, @zyp also ported code snippet to C - but for some reason it is "not working" - see transfer_byte below static uint32_t transfer_byte(uint8_t b)
{
// wait for tx ready
while(!spiflash_mmap_master_status_tx_ready_read())
;
spiflash_mmap_master_rxtx_write((uint32_t)b);
//wait for rx ready
while(!spiflash_mmap_master_status_rx_ready_read())
;
return spiflash_mmap_master_rxtx_read();
} any idea? |
What exactly is not working? Have you scoped the signals? Did you assert CS first? |
Oh, my bad, the line setting
|
@zyp |
@zyp, @norbertthiel: Very interesting. @norbertthiel I'm currently improving LiteSPI integration with LiteX and LiteX-Boards and want to do an equivalent of https://github.com/enjoy-digital/litex/blob/master/litex/soc/software/libbase/spiflash.c for LiteSPI which is from what I understand what you just did :) Is is something you would like to contribute to project and so that we could use in in https://github.com/enjoy-digital/litex/tree/master/litex/soc/software/liblitespi and integrate it to the BIOS commands? |
Hmm sorry, this is the code snippet you just posted before and it also seems to be part of enjoy-digital/litex#979. I'm going to look at that, but if you want to share your code it can still be useful. |
porting above python code to C - allowing to spiflash_sector_erase and spiflash_write_stream etc... //IMPLEMENT writing to SPI Flash
static uint8_t w_buf[SPI_FLASH_BLOCK_SIZE + 4];
static uint8_t r_buf[SPI_FLASH_BLOCK_SIZE + 4];
static uint32_t transfer_byte(uint8_t b)
{
// wait for tx ready
while(!spiflash_core_master_status_tx_ready_read())
;
spiflash_core_master_rxtx_write((uint32_t)b);
//wait for rx ready
while(!spiflash_core_master_status_rx_ready_read())
;
return spiflash_core_master_rxtx_read();
}
static void transfer_cmd(uint8_t *bs, uint8_t *resp, int len)
{
spiflash_core_master_phyconfig_len_write(8);
spiflash_core_master_phyconfig_width_write(1);
spiflash_core_master_phyconfig_mask_write(1);
spiflash_core_master_cs_write(1);
for(int i=0; i < len; i++)
resp[i] = transfer_byte(bs[i]);
spiflash_core_master_cs_write(0);
}
uint32_t spiflash_read_status_register(void)
{
uint8_t buf[2];
w_buf[0] = 0x05;
w_buf[1] = 0x00;
transfer_cmd(w_buf, buf, 2);
return buf[1];
}
void spiflash_write_enable(void)
{
uint8_t buf[1];
w_buf[0] = 0x06;
transfer_cmd(w_buf, buf, 1);
}
static void page_program(void *addr, uint8_t *data, int len)
{
w_buf[0] = 0x02;
w_buf[1] = ((uint32_t)addr)>>16;
w_buf[2] = ((uint32_t)addr)>>8;
w_buf[3] = ((uint32_t)addr)>>0;
memcpy(w_buf+4, data, len);
transfer_cmd(w_buf, r_buf, len+4);
}
void spiflash_sector_erase(void *addr)
{
w_buf[0] = 0x20;
w_buf[1] = ((uint32_t)addr)>>16;
w_buf[2] = ((uint32_t)addr)>>8;
w_buf[3] = ((uint32_t)addr)>>0;
transfer_cmd(w_buf, r_buf, 4);
}
#define min(x, y) (((x) < (y)) ? (x) : (y))
int spiflash_write_stream(void *addr, uint8_t *stream, int len)
{
int res = 0;
if( ((uint32_t)addr & (SPI_FLASH_ERASE_SIZE - 1)) == 0)
{
int w_len = min(len, SPI_FLASH_BLOCK_SIZE);
int offset = 0;
while(w_len)
{
if(((uint32_t)addr+offset) & (SPI_FLASH_ERASE_SIZE - 1) == 0)
{
spiflash_write_enable();
sector_erase(addr+offset);
while (spiflash_read_status_register() & 1)
;
}
spiflash_write_enable();
page_program(addr+offset, stream+offset, w_len);
while(spiflash_read_status_register() & 1)
;
offset += w_len;
w_len = min(len-offset,SPI_FLASH_BLOCK_SIZE);
res = offset;
}
}
return res;
} |
The code is based on norbert thiel's comment litex-hub/litespi#52 But edited to work with W25Q128JVS flash used in MNT RKX7.
How to use litespi to perform flash write?
I am trying to integrate litespi and use bios to download images to flash.
The text was updated successfully, but these errors were encountered: