|
|
@ -1,23 +1,3 @@
|
|
|
|
/**
|
|
|
|
|
|
|
|
* @file flash.c
|
|
|
|
|
|
|
|
* Provides functionality for using an external SPI flash
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* Copyright (C) 2018 Clyne Sullivan
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
|
|
|
|
* (at your option) any later version.
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
|
|
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include <stm32l476xx.h>
|
|
|
|
#include <stm32l476xx.h>
|
|
|
|
#include <gpio.h>
|
|
|
|
#include <gpio.h>
|
|
|
|
#include <clock.h>
|
|
|
|
#include <clock.h>
|
|
|
@ -27,89 +7,111 @@
|
|
|
|
#define WREN 0x06
|
|
|
|
#define WREN 0x06
|
|
|
|
#define WRDS 0x04
|
|
|
|
#define WRDS 0x04
|
|
|
|
|
|
|
|
|
|
|
|
#define NSS GPIO_PORT(B, 12)
|
|
|
|
#define SCK GPIO_PORT(C, 14)
|
|
|
|
#define SCK GPIO_PORT(B, 13)
|
|
|
|
#define SI GPIO_PORT(C, 3)
|
|
|
|
#define MISO GPIO_PORT(B, 14)
|
|
|
|
#define SO GPIO_PORT(C, 2)
|
|
|
|
#define MOSI GPIO_PORT(B, 15)
|
|
|
|
#define CS GPIO_PORT(C, 15)
|
|
|
|
|
|
|
|
|
|
|
|
void flash_xchg(char *byte, int count);
|
|
|
|
void flash_out(uint8_t);
|
|
|
|
|
|
|
|
uint8_t flash_in(void);
|
|
|
|
|
|
|
|
|
|
|
|
void flash_init(void)
|
|
|
|
void flash_init(void)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
gpio_mode(NSS, ALTERNATE);
|
|
|
|
gpio_mode(SCK, OUTPUT);
|
|
|
|
gpio_mode(SCK, ALTERNATE);
|
|
|
|
gpio_mode(SI, OUTPUT);
|
|
|
|
gpio_mode(MISO, ALTERNATE);
|
|
|
|
gpio_mode(CS, OUTPUT);
|
|
|
|
gpio_mode(MOSI, ALTERNATE);
|
|
|
|
gpio_mode(SO, OUTPUT);
|
|
|
|
GPIOB->AFR[1] |= 0x55550000; // alt mode SPI2
|
|
|
|
gpio_dout(SO, 0);
|
|
|
|
|
|
|
|
gpio_mode(SO, INPUT);
|
|
|
|
|
|
|
|
gpio_dout(CS, 1);
|
|
|
|
|
|
|
|
gpio_dout(SCK, 0);
|
|
|
|
|
|
|
|
gpio_dout(SI, 0);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//RCC->AHB3ENR |= RCC_AHB3ENR_QSPIEN;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//// 10MHz operation, per datasheet
|
|
|
|
|
|
|
|
//QUADSPI->CR &= ~(0xFF << QUADSPI_CR_PRESCALER_Pos);
|
|
|
|
|
|
|
|
//QUADSPI->CR |= 7 << QUADSPI_CR_PRESCALER_Pos;
|
|
|
|
|
|
|
|
|
|
|
|
// clock enable
|
|
|
|
//// pick FSEL! 0=1, 1=2
|
|
|
|
RCC->APB1ENR1 |= RCC_APB1ENR1_SPI2EN;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
SPI2->CR1 &= ~(SPI_CR1_BR_Msk);
|
|
|
|
//// FSIZE = 16, 2^17 bits = 1Mb
|
|
|
|
SPI2->CR1 |= (3 << SPI_CR1_BR_Pos);
|
|
|
|
//QUADSPI->DCR = (16 << QUADSPI_DCR_FSIZE_Pos);
|
|
|
|
SPI2->CR1 |= SPI_CR1_SSM | SPI_CR1_SSI;
|
|
|
|
|
|
|
|
SPI2->CR1 |= SPI_CR1_MSTR;
|
|
|
|
|
|
|
|
SPI2->CR2 &= ~(SPI_CR2_DS_Msk);
|
|
|
|
|
|
|
|
SPI2->CR2 |= (7 << SPI_CR2_DS_Pos);
|
|
|
|
|
|
|
|
SPI2->CR2 |= SPI_CR2_SSOE;
|
|
|
|
|
|
|
|
SPI2->CR2 |= SPI_CR2_FRXTH;
|
|
|
|
|
|
|
|
SPI2->CR1 |= SPI_CR1_SPE;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
char buf[4];
|
|
|
|
//// Memmap mode, single-spi
|
|
|
|
buf[0] = READ;
|
|
|
|
//QUADSPI->CCR = (3 << QUADSPI_CCR_FMODE_Pos) | (1 << QUADSPI_CCR_DMODE_Pos)
|
|
|
|
buf[1] = 0;
|
|
|
|
// | (2 << QUADSPI_CCR_ADSIZE_Pos) | (1 << QUADSPI_CCR_ADMODE_Pos)
|
|
|
|
buf[2] = 0;
|
|
|
|
// | (1 << QUADSPI_CCR_IMODE_Pos);
|
|
|
|
buf[3] = 0;
|
|
|
|
//// TODO CCR also takes instruction byte
|
|
|
|
flash_xchg(buf, 4);
|
|
|
|
//QUADSPI->CCR |= (READ << QUADSPI_CCR_INSTRUCTION_Pos);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//QUADSPI->CR |= QUADSPI_CR_EN;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void flash_xchg(char *byte, int count)
|
|
|
|
void flash_out(uint8_t byte)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
uint32_t status = 0, dummy;
|
|
|
|
for (uint8_t i = 0; i < 8; i++) {
|
|
|
|
SPI2->CR1 &= ~(SPI_CR1_SSI);
|
|
|
|
gpio_dout(SI, (byte & (1 << (7 - i))));
|
|
|
|
while (SPI2->SR & SPI_SR_BSY);
|
|
|
|
gpio_dout(SCK, 1);
|
|
|
|
for (int i = 0; i < count; i++) {
|
|
|
|
delay(1);
|
|
|
|
SPI2->DR = byte[i];
|
|
|
|
gpio_dout(SCK, 0);
|
|
|
|
do status = SPI2->SR;
|
|
|
|
|
|
|
|
while (status & SPI_SR_BSY);
|
|
|
|
|
|
|
|
// discard rx
|
|
|
|
|
|
|
|
while (status & SPI_SR_RXNE) {
|
|
|
|
|
|
|
|
dummy = SPI2->DR;
|
|
|
|
|
|
|
|
status = SPI2->SR;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
do status = SPI2->SR;
|
|
|
|
}
|
|
|
|
while (status & SPI_SR_BSY);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
void flash_addr(uint32_t addr)
|
|
|
|
SPI2->DR = 0;
|
|
|
|
{
|
|
|
|
do status = SPI2->SR;
|
|
|
|
for (uint8_t i = 0; i < 24; i++) {
|
|
|
|
while (status & SPI_SR_BSY);
|
|
|
|
gpio_dout(SI, (addr & (1 << (23 - i))));
|
|
|
|
// discard rx
|
|
|
|
gpio_dout(SCK, 1);
|
|
|
|
while (status & SPI_SR_RXNE) {
|
|
|
|
delay(1);
|
|
|
|
dummy = SPI2->DR;
|
|
|
|
gpio_dout(SCK, 0);
|
|
|
|
status = SPI2->SR;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
SPI2->CR1 |= SPI_CR1_SSI;
|
|
|
|
uint8_t flash_in(void)
|
|
|
|
(void)dummy;
|
|
|
|
{
|
|
|
|
|
|
|
|
uint8_t byte = 0;
|
|
|
|
|
|
|
|
for (uint8_t i = 0; i < 8; i++) {
|
|
|
|
|
|
|
|
gpio_dout(SCK, 1);
|
|
|
|
|
|
|
|
delay(1);
|
|
|
|
|
|
|
|
gpio_dout(SCK, 0);
|
|
|
|
|
|
|
|
if (gpio_din(SO))
|
|
|
|
|
|
|
|
byte |= (1 << (7 - i));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return byte;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void flash_read(char *buf, uint32_t addr, unsigned int count)
|
|
|
|
void flash_read(char *buf, uint32_t addr, unsigned int count)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
(void)buf;
|
|
|
|
|
|
|
|
(void)addr;
|
|
|
|
|
|
|
|
(void)count;
|
|
|
|
|
|
|
|
if (buf == 0)
|
|
|
|
if (buf == 0)
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
|
|
|
|
gpio_dout(CS, 0);
|
|
|
|
|
|
|
|
delay(1);
|
|
|
|
|
|
|
|
flash_out(READ);
|
|
|
|
|
|
|
|
flash_addr(addr);
|
|
|
|
|
|
|
|
for (unsigned int i = 0; i < count; i++)
|
|
|
|
|
|
|
|
buf[i] = flash_in();
|
|
|
|
|
|
|
|
gpio_dout(CS, 1);
|
|
|
|
|
|
|
|
delay(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void flash_write(const char *buf, uint32_t addr, unsigned int count)
|
|
|
|
void flash_write(const char *buf, uint32_t addr, unsigned int count)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
(void)buf;
|
|
|
|
|
|
|
|
(void)addr;
|
|
|
|
|
|
|
|
(void)count;
|
|
|
|
|
|
|
|
if (buf == 0)
|
|
|
|
if (buf == 0)
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
|
|
|
|
gpio_dout(CS, 0);
|
|
|
|
|
|
|
|
delay(1);
|
|
|
|
|
|
|
|
flash_out(WREN);
|
|
|
|
|
|
|
|
gpio_dout(CS, 1);
|
|
|
|
|
|
|
|
delay(100);
|
|
|
|
|
|
|
|
gpio_dout(CS, 0);
|
|
|
|
|
|
|
|
flash_out(WRITE);
|
|
|
|
|
|
|
|
flash_addr(addr);
|
|
|
|
|
|
|
|
for (unsigned int i = 0; i < count; i++)
|
|
|
|
|
|
|
|
flash_out(buf[i]);
|
|
|
|
|
|
|
|
gpio_dout(CS, 1);
|
|
|
|
|
|
|
|
delay(100);
|
|
|
|
|
|
|
|
//gpio_dout(CS, 0);
|
|
|
|
|
|
|
|
//flash_out(WRDS);
|
|
|
|
|
|
|
|
//gpio_dout(CS, 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|