我有一个带有stm32l476和w25q128jv qspi的自制板。我总是将此QSPI与其他stm32一起使用。我尝试使用此qspi以及带有stm32h7和stm32f7的软件,并且都可以正常工作,但是我不明白为什么使用stm32l476无法正常工作。
我使用的针脚是:
GPIOE_10 --> QUADSPI_CLK
GPIOE_11 --> QUADSPI_NCS
GPIOE_12 --> QUADSPI_BK1_IO0
GPIOE_13 --> QUADSPI_BK1_IO1
GPIOE_14 --> QUADSPI_BK1_IO2
GPIOE_15 --> QUADSPI_BK1_IO3
我有一个上拉电阻,用于NCS到3.3V,电容器在3.3V和GND之间。
当我在位置0x90000000写入256字节的'0x23' 以及其他256字节的“ 0xf3”在位置0x90000100
它写成这样:
我以这种方式使用我的软件:
init_qspi_pin();
init_qspi();
擦除qspi
qspi_write_array();
这是我的软件:
QSPI INIT:
unsigned char init_qspi(){
unsigned long c1;
unsigned long pass_addr;
unsigned char passchar;
unsigned long passlong;
unsigned long passlong2;
//** DEINIT **
//DISABLE QSPI
QUADSPI->CR &= ~(QUADSPI_CR_EN);
//SPI FORCE RESET
RCC->AHB3RSTR |= RCC_AHB3RSTR_QSPIRST;
//SPI FORCE RELEASE
RCC->AHB3RSTR &= ~(RCC_AHB3RSTR_QSPIRST);
//DISABLE QSPI MEMORY INTERFACE CLOCK
RCC->AHB3ENR &= ~(RCC_AHB3ENR_QSPIEN);
//** INIT **
//ENABLE QSPI MEMORY INTERFACE CLOCK
RCC->AHB3ENR |= RCC_AHB3ENR_QSPIEN;
while ((RCC->AHB3ENR & RCC_AHB3ENR_QSPIEN) == 0)
{
}
passlong = 1;
//SPI FORCE RESET
RCC->AHB3RSTR |= RCC_AHB3RSTR_QSPIRST;
//SPI FORCE RELEASE
RCC->AHB3RSTR &= ~(RCC_AHB3RSTR_QSPIRST);
//ENABLE QSPI PINS CLOCK
init_QSPI_pin();
QUADSPI->CR = 0x00000000;
//SET QSPI FIFO THREESHOLD (4)
passlong = 4;
QUADSPI->CR |= ((passlong-1) << 8);
//WAIT QSPI BUSY FLAG RESET
while(QUADSPI->SR & QUADSPI_SR_BUSY){
}
//SET QSPI CLOCK PRESCALER = 1 (Fahb/2)
QUADSPI->CR |= (1 << 24);
//SET SAMPLE SHIFT (1/2 CYCLE)
QUADSPI->CR |= (1 << 4);
//SET FLASH SIZE (128 Mbit)
QUADSPI->DCR |= (0x17 << 16);
//SET CS HIGH TIME BETWEEN COMMANDS (2 clk cycles --> SET CSHT = CLK CYCLES - 1 = 1)
QUADSPI->DCR |= (1 << 8);
//SET THE LEVEL THAT CLK TAKES BETWEEN COMMANDS (WHEN CS IS HIGH).
QUADSPI->DCR |= 0; //(LOW LEVEL)
//IMODE (INSTRUCTION MODE) = ON A SINGLE LINE
QUADSPI->CCR |= QUADSPI_CCR_IMODE_0;
QUADSPI->CCR &= ~(QUADSPI_CCR_ADSIZE);
QUADSPI->CCR |= QUADSPI_CCR_ADSIZE_1;
//ENABLE QSPI PERIPHERAL
QUADSPI->CR |= QUADSPI_CR_EN;
CMD_READ_QUAD_OUT = 0x6B;
CMD_ERASE_4K_SECTOR = 0x20;
CMD_QUAD_PAGE_PROGRAM = 0x32;
return 0;
}
内存映射:
void qspi_memory_mapped()
{
unsigned char config_reg = 0x00;
unsigned char status_reg = 0x00;
volatile unsigned long *data_register;
data_register = &QUADSPI->DR;
//DATA MODE = DATA ON 4 LINES
QUADSPI->CCR |= (QUADSPI_CCR_DMODE_0 | QUADSPI_CCR_DMODE_1);
//ADDRESS MODE = ADDRESS ON A SINGLE LINE
QUADSPI->CCR |= QUADSPI_CCR_ADMODE_0;
//RESET TRANSFER FLAG
qspi_reset_flags();
//SET INSTRUCTION
QUADSPI->CCR |= CMD_READ_QUAD_OUT;
// DUMMY CLOCK CYCLES = 8
QUADSPI->CCR |= QUADSPI_CCR_DCYC;
//FUNCTIONAL MODE (MEMORY MAPPED)
QUADSPI->CCR |= (QUADSPI_CCR_FMODE_1 | QUADSPI_CCR_FMODE_0);
// SET ADDRESS TO READ
QUADSPI->AR = 0x00000000;
}
写解锁:
void qspi_write_unlock()
{
unsigned long passlong=0;
QUADSPI->DLR = 0;
//DATA MODE = NO DATA
//QUADSPI->CCR |= 0;
//ADDRESS MODE = NO ADDRESS
//QUADSPI->CCR |= 0;
//RESET TRANSFER FLAG
qspi_reset_flags();
//SET INSTRUCTION TRIG!!
QUADSPI->CCR |= CMD_WRITE_ENABLE;
//FUNCTIONAL MODE (write)
//QUADSPI->CCR |= 0;
wait_transfer_complete();
//RESET FMODE, DMODE, AMODE E INSTRUCTION
QUADSPI->CCR &= ~(QUADSPI_CCR_FMODE | QUADSPI_CCR_DMODE | QUADSPI_CCR_ADMODE | QUADSPI_CCR_INSTRUCTION);
//RESET TRANSFER FLAG
qspi_reset_flags();
qspi_wait_device();
}
启用四路公交车:
void qspi_enable_quad_bus(unsigned char enable)
{
unsigned long passlong=0;
unsigned char config_reg = 0x00;
unsigned char status_reg = 0x00;
unsigned long data_reg = 0x00000000;
qspi_write_unlock();
QUADSPI->DLR = 1; //SI SCRIVONO 2 BYTE
//DATA MODE = DATA ON A SINGLE LINE
QUADSPI->CCR |= QUADSPI_CCR_DMODE_0;
//ADDRESS MODE = NO ADDRESS
//QUADSPI->CCR |= 0;
//RESET TRANSFER FLAG
qspi_reset_flags();
//SET INSTRUCTION
QUADSPI->CCR |= CMD_WRITE_REGISTER;
if (enable){
config_reg = 0x02;
}
data_reg = config_reg;
data_reg <<= 8;
data_reg |= status_reg;
// SET DATA TO SEND TRIG!!
QUADSPI->DR = data_reg;
//FUNCTIONAL MODE (write)
//QUADSPI->CCR |= 0;
wait_transfer_complete();
//RESET FMODE, DMODE, AMODE E INSTRUCTION
QUADSPI->CCR &= ~(QUADSPI_CCR_FMODE | QUADSPI_CCR_DMODE | QUADSPI_CCR_ADMODE | QUADSPI_CCR_INSTRUCTION);
//RESET TRANSFER FLAG
qspi_reset_flags();
qspi_wait_device();
}
QSPI读寄存器:
unsigned char qspi_read_register(unsigned char read_reg_cmd)
{
unsigned long passlong;
unsigned long *p_ulong;
QUADSPI->DLR = 1;
//DATA MODE = DATA ON 1 LINE
QUADSPI->CCR |= QUADSPI_CCR_DMODE_0;
//ADDRESS MODE = NO ADDRESS
//QUADSPI->CCR |= 0;
//SET INSTRUCTION
QUADSPI->CCR |= read_reg_cmd;
//FUNCTIONAL MODE (INDIRECT READ) TRIG!!
QUADSPI->CCR |= QUADSPI_CCR_FMODE_0;
//wait_transfer_complete();
passlong = QUADSPI->DR;
//RESET FMODE, DMODE, AMODE E INSTRUCTION
QUADSPI->CCR &= ~(QUADSPI_CCR_FMODE | QUADSPI_CCR_DMODE | QUADSPI_CCR_ADMODE | QUADSPI_CCR_INSTRUCTION);
//RESET TRANSFER FLAG
qspi_reset_flags();
return (unsigned char)passlong;
}
QSPI等待设备:
void qspi_wait_device()
{
unsigned char passchar;
do
{
//WAIT UNTILL THE FLAG "WRITE IN PROGRESS" NOT RESET
passchar = qspi_read_register(CMD_READ_STATUS_REGISTER_1);
}
while(passchar & 0x01);
}
QSPI从内存读取数组:
unsigned char qspi_read_array(unsigned long start_address, unsigned char *p_data, unsigned long data_len)
{
unsigned char config_reg = 0x00;
unsigned char status_reg = 0x00;
volatile unsigned long *data_register;
if (start_address + data_len > QSPI_TOTAL_SIZE)
{
return 1;
}
data_register = &QUADSPI->DR;
QUADSPI->DLR = data_len - 1;
//DATA MODE = DATA ON 4 LINES
QUADSPI->CCR |= (QUADSPI_CCR_DMODE_0 | QUADSPI_CCR_DMODE_1);
//ADDRESS MODE = ADDRESS ON A SINGLE LINE
QUADSPI->CCR |= QUADSPI_CCR_ADMODE_0;
//RESET TRANSFER FLAG
qspi_reset_flags();
//SET INSTRUCTION
QUADSPI->CCR |= CMD_READ_QUAD_OUT;
// DUMMY CLOCK CYCLES = 8
QUADSPI->CCR |= QUADSPI_CCR_DCYC;
//FUNCTIONAL MODE (READ)
QUADSPI->CCR |= QUADSPI_CCR_FMODE_0;
// SET ADDRESS TO READ TRIG!!
QUADSPI->AR = start_address;
while(data_len)
{
while(QUADSPI->SR & QUADSPI_SR_FTF)
{
if (data_len)
{
*p_data = *(__IO uint8_t *)data_register;
p_data++;
data_len--;
if (QUADSPI->SR & QUADSPI_SR_TEF)
{
//TRANSFER ERROR
return 1;
}
}
else
{
break;
}
}
}
wait_transfer_complete();
//reset FMODE, DMODE, AMODE, INSTRUCTION E DUMMY CYCLES
QUADSPI->CCR &= ~(QUADSPI_CCR_FMODE | QUADSPI_CCR_DMODE | QUADSPI_CCR_ADMODE | QUADSPI_CCR_INSTRUCTION | QUADSPI_CCR_DCYC);
QUADSPI->DLR = 0;
//RESET TRANSFER FLAG
qspi_reset_flags();
qspi_wait_device();
return 0;
}
QSPI擦除:
void qspi_erase_sector(unsigned long sector_id)
{
unsigned char config_reg = 0x00;
unsigned char status_reg = 0x00;
unsigned long data = 0x00000000;
unsigned long passlong;
QUADSPI->DLR = 0;
//DATA MODE = NO DATA
//QUADSPI->CCR |= 0;
//ADDRESS MODE = ADDRESS ON A SINGLE LINE
QUADSPI->CCR |= QUADSPI_CCR_ADMODE_0;
//RESET TRANSFER FLAG
qspi_reset_flags();
//SET INSTRUCTION
switch(qspi_get_sector_size(sector_id))
{
case (4*1024):
{
QUADSPI->CCR |= CMD_ERASE_4K_SECTOR;
break;
}
case (64*1024):
{
QUADSPI->CCR |= CMD_ERASE_64K_SECTOR;
break;
}
default:
QUADSPI->CCR |= CMD_ERASE_4K_SECTOR;
break;
}
QUADSPI->AR = passlong;
wait_transfer_complete();
//reset FMODE, DMODE, AMODE, INSTRUCTION E DUMMY CYCLES
QUADSPI->CCR &= ~(QUADSPI_CCR_FMODE | QUADSPI_CCR_DMODE | QUADSPI_CCR_ADMODE | QUADSPI_CCR_INSTRUCTION | QUADSPI_CCR_DCYC);
//RESET TRANSFER FLAG
qspi_reset_flags();
qspi_wait_device();
}
QSPI写锁:
void qspi_write_lock()
{
QUADSPI->DLR = 0;
//DATA MODE = NO DATA
//QUADSPI->CCR |= 0;
//ADDRESS MODE = NO ADDRESS
//QUADSPI->CCR |= 0;
//RESET TRANSFER FLAG
qspi_reset_flags();
//SET INSTRUCTION TRIG!!
QUADSPI->CCR |= CMD_WRITE_DISABLE;
//FUNCTIONAL MODE (write)
//QUADSPI->CCR |= 0;
wait_transfer_complete();
//RESET FMODE, DMODE, AMODE E INSTRUCTION
QUADSPI->CCR &= ~(QUADSPI_CCR_FMODE | QUADSPI_CCR_DMODE | QUADSPI_CCR_ADMODE | QUADSPI_CCR_INSTRUCTION);
//RESET TRANSFER FLAG
qspi_reset_flags();
qspi_wait_device();
}
QSPI四页程序:
unsigned char qspi_quad_page_program(unsigned long start_address, unsigned char *p_data, unsigned long data_len){
unsigned long c1;
unsigned char passchar;
unsigned long data = 0x00000000;
volatile unsigned long *data_register;
unsigned char write_error;
unsigned long passlong;
if (data_len == 0){
return 1;
}
data_register = &QUADSPI->DR;
QUADSPI->DLR = data_len - 1; //BYTES TO WRITE
//DATA MODE = DATA ON 4 LINES
QUADSPI->CCR |= (QUADSPI_CCR_DMODE_0 | QUADSPI_CCR_DMODE_1);
//ADDRESS MODE = ADDRESS ON A SINGLE LINE
QUADSPI->CCR |= QUADSPI_CCR_ADMODE_0;
//RESET TRANSFER FLAG
qspi_reset_flags();
//SET INSTRUCTION
QUADSPI->CCR |= CMD_QUAD_PAGE_PROGRAM;
//SET QSPI ADDRESS
QUADSPI->AR = start_address;
//FUNCTIONAL MODE (WRITE)
//QUADSPI->CCR |= 0;
qspi_buffer_len = data_len;
qspi_buffer = p_data;
while(qspi_buffer_len > 0){
while(QUADSPI->SR & QUADSPI_SR_FTF){
if (qspi_buffer_len){
*(__IO uint8_t *)data_register = *qspi_buffer;
qspi_buffer++;
qspi_buffer_len--;
if (QUADSPI->SR & QUADSPI_SR_TEF){
//TRANSFER ERROR
return 1;
}
}
else
{
break;
}
}
}
while (QUADSPI->SR & QUADSPI_SR_BUSY){
c1++;
c1--;
}
//RESET FMODE, DMODE, AMODE, INSTRUCTION E DUMMY CYCLES
QUADSPI->CCR &= ~(QUADSPI_CCR_FMODE | QUADSPI_CCR_DMODE | QUADSPI_CCR_ADMODE | QUADSPI_CCR_INSTRUCTION | QUADSPI_CCR_DCYC);
QUADSPI->DLR = 0;
qspi_reset_flags();
write_error = qspi_write_error_occurred();
if (write_error){
return 1;
}
qspi_wait_device();
return 0;
}
QSPI错误:
unsigned char qspi_write_error_occurred()
{
unsigned char passchar;
passchar = qspi_read_register(CMD_READ_STATUS_REGISTER_1);
if(passchar & (0x01 << 6))
{
return 1;
}
return 0;
}
QSPI写数组:
unsigned char qspi_write_array(unsigned long start_address, unsigned char *p_data, unsigned long data_len)
{
unsigned long c1, c2, c3;
//unsigned long page_start_addr;
unsigned char write_error;
unsigned long pages_to_write;
unsigned long remaining_bytes;
unsigned char passchar;
unsigned char *data_ptr;
unsigned long qspi_idx;
if (start_address + data_len > QSPI_TOTAL_SIZE){
return 1;
}
qspi_enable_quad_bus(1);
qspi_idx = start_address;
data_ptr = p_data;
pages_to_write = data_len / QSPI_PAGE_SIZE;
for(c1=0; c1 < pages_to_write; c1++)
{
qspi_write_unlock();
if(qspi_quad_page_program(qspi_idx, data_ptr, QSPI_PAGE_SIZE)){
//ERROR
return 1;
}
qspi_write_lock();
qspi_idx += QSPI_PAGE_SIZE;
data_ptr += QSPI_PAGE_SIZE;
}
remaining_bytes = data_len % QSPI_PAGE_SIZE;
if (remaining_bytes){
qspi_write_unlock();
if(qspi_quad_page_program(qspi_idx, data_ptr, remaining_bytes)){
//ERROR
return 1;
}
qspi_write_lock();
}
return 0;
}
QSPI GET模型:
unsigned short qspi_get_model()
{
unsigned long device_id;
unsigned long device_info;
device_id = qspi_read_device_id();
device_id = qspi_read_device_id();
device_info = qspi_read_device_info();
if((device_id == 0x000017EF)&&
(device_info == 0x001870EF)){
return QSPI_MODEL__W25Q128JV;
}
else if((device_id == 0x00001701)&&
(device_info == 0x00182001)){
return QSPI_MODEL__S25FL128S;
}
else if((device_info == 0x0018BA20)){
return QSPI_MODEL__MIA;
}
return 0x0000;
}
QSPI信息:
unsigned long qspi_read_device_info()
{
unsigned long passlong;
unsigned long *p_ulong;
QUADSPI->DLR = 2;
//DATA MODE = DATA ON 1 LINE
QUADSPI->CCR |= QUADSPI_CCR_DMODE_0;
//ADDRESS MODE = NO ADDRESS
QUADSPI->CCR &= ~(QUADSPI_CCR_ADMODE);
//SET INSTRUCTION
QUADSPI->CCR |= CMD_READ_DEV_INFO;
//FUNCTIONAL MODE
QUADSPI->CCR |= QUADSPI_CCR_FMODE_0;
//FLASH ADDRESS
QUADSPI->AR = 0x00000000;
wait_transfer_complete();
passlong = QUADSPI->DR;
//RESET TRANSFER FLAG
qspi_reset_flags();
//RESET FMODE, DMODE, AMODE E INSTRUCTION
QUADSPI->CCR &= ~(QUADSPI_CCR_FMODE | QUADSPI_CCR_DMODE | QUADSPI_CCR_ADMODE | QUADSPI_CCR_INSTRUCTION);
//RESET TRANSFER FLAG
qspi_reset_flags();
return passlong;
}
QSPI读取信息:
unsigned long qspi_read_device_id()
{
unsigned long passlong;
unsigned long *p_ulong;
QUADSPI->DLR = 1;
//DATA MODE = DATA ON 1 LINE
QUADSPI->CCR |= QUADSPI_CCR_DMODE_0;
//ADDRESS MODE = ADDRESS ON ONE LINE
QUADSPI->CCR |= QUADSPI_CCR_ADMODE_0;
//SET INSTRUCTION
QUADSPI->CCR |= CMD_READ_DEVICE_ID;
//FUNCTIONAL MODE
QUADSPI->CCR |= QUADSPI_CCR_FMODE_0;
//RESET TRANSFER FLAG
qspi_reset_flags();
//FLASH ADDRESS
QUADSPI->AR = 0x00000000;
wait_transfer_complete();
passlong = QUADSPI->DR;
//RESET FMODE, DMODE, AMODE E INSTRUCTION
QUADSPI->CCR &= ~(QUADSPI_CCR_FMODE | QUADSPI_CCR_DMODE | QUADSPI_CCR_ADMODE | QUADSPI_CCR_INSTRUCTION);
//RESET TRANSFER FLAG
qspi_reset_flags();
return passlong;
}
QSPI读取信息:
unsigned long qspi_read_info(unsigned char instruction,unsigned char nByteToRead)
{
unsigned long passlong;
unsigned long *p_ulong;
QUADSPI->DLR = nByteToRead - 1;
//DATA MODE = DATA ON 1 LINE
QUADSPI->CCR |= QUADSPI_CCR_DMODE_0;
//ADDRESS MODE = ADDRESS ON ONE LINE
QUADSPI->CCR |= QUADSPI_CCR_ADMODE_0;
//SET INSTRUCTION
QUADSPI->CCR |= instruction;
//FUNCTIONAL MODE
QUADSPI->CCR |= QUADSPI_CCR_FMODE_0;
//RESET TRANSFER FLAG
qspi_reset_flags();
//FLASH ADDRESS
QUADSPI->AR = 0x00000000;
wait_transfer_complete();
passlong = QUADSPI->DR;
//RESET FMODE, DMODE, AMODE E INSTRUCTION
QUADSPI->CCR &= ~(QUADSPI_CCR_FMODE | QUADSPI_CCR_DMODE | QUADSPI_CCR_ADMODE | QUADSPI_CCR_INSTRUCTION);
//RESET TRANSFER FLAG
qspi_reset_flags();
return passlong;
}
QSPI重置标志
void qspi_reset_flags()
{
unsigned char c1;
while (QUADSPI->SR & QUADSPI_SR_BUSY)
{
}
END:
QUADSPI->FCR = 0xFFFFFFFF;
}
QSPI等待TRASFERT完成:
void wait_transfer_complete()
{
while ((QUADSPI->SR & QUADSPI_SR_TCF) == 0)
{
}
}
有人可以帮助我吗?
答案 0 :(得分:0)
内存映射模式:在此模式下,仅允许对外部闪存进行读取操作。