原始版本
This commit is contained in:
379
Libraries/HAL_Drivers/drivers/drv_qspi.c
Normal file
379
Libraries/HAL_Drivers/drivers/drv_qspi.c
Normal file
@ -0,0 +1,379 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2018-11-27 zylx first version
|
||||
*/
|
||||
|
||||
#include "board.h"
|
||||
#include "drv_qspi.h"
|
||||
#include "drv_config.h"
|
||||
|
||||
#ifdef RT_USING_QSPI
|
||||
|
||||
#define DRV_DEBUG
|
||||
#define LOG_TAG "drv.qspi"
|
||||
#include <drv_log.h>
|
||||
|
||||
#if defined(BSP_USING_QSPI)
|
||||
|
||||
struct stm32_qspi_bus
|
||||
{
|
||||
QSPI_HandleTypeDef QSPI_Handler;
|
||||
char *bus_name;
|
||||
#ifdef BSP_QSPI_USING_DMA
|
||||
DMA_HandleTypeDef hdma_quadspi;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct rt_spi_bus _qspi_bus1;
|
||||
struct stm32_qspi_bus _stm32_qspi_bus;
|
||||
|
||||
static int stm32_qspi_init(struct rt_qspi_device *device, struct rt_qspi_configuration *qspi_cfg)
|
||||
{
|
||||
int result = RT_EOK;
|
||||
unsigned int i = 1;
|
||||
|
||||
RT_ASSERT(device != RT_NULL);
|
||||
RT_ASSERT(qspi_cfg != RT_NULL);
|
||||
|
||||
struct rt_spi_configuration *cfg = &qspi_cfg->parent;
|
||||
struct stm32_qspi_bus *qspi_bus = device->parent.bus->parent.user_data;
|
||||
rt_memset(&qspi_bus->QSPI_Handler, 0, sizeof(qspi_bus->QSPI_Handler));
|
||||
|
||||
QSPI_HandleTypeDef QSPI_Handler_config = QSPI_BUS_CONFIG;
|
||||
qspi_bus->QSPI_Handler = QSPI_Handler_config;
|
||||
|
||||
#if defined(SOC_SERIES_STM32MP1)
|
||||
while (cfg->max_hz < HAL_RCC_GetACLKFreq() / (i + 1))
|
||||
#else
|
||||
while (cfg->max_hz < HAL_RCC_GetHCLKFreq() / (i + 1))
|
||||
#endif
|
||||
{
|
||||
i++;
|
||||
if (i == 255)
|
||||
{
|
||||
LOG_E("QSPI init failed, QSPI frequency(%d) is too low.", cfg->max_hz);
|
||||
return -RT_ERROR;
|
||||
}
|
||||
}
|
||||
/* 80/(1+i) */
|
||||
qspi_bus->QSPI_Handler.Init.ClockPrescaler = i;
|
||||
|
||||
if (!(cfg->mode & RT_SPI_CPOL))
|
||||
{
|
||||
/* QSPI MODE0 */
|
||||
qspi_bus->QSPI_Handler.Init.ClockMode = QSPI_CLOCK_MODE_0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* QSPI MODE3 */
|
||||
qspi_bus->QSPI_Handler.Init.ClockMode = QSPI_CLOCK_MODE_3;
|
||||
}
|
||||
|
||||
/* flash size */
|
||||
qspi_bus->QSPI_Handler.Init.FlashSize = POSITION_VAL(qspi_cfg->medium_size) - 1;
|
||||
|
||||
result = HAL_QSPI_Init(&qspi_bus->QSPI_Handler);
|
||||
if (result == HAL_OK)
|
||||
{
|
||||
LOG_D("qspi init success!");
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_E("qspi init failed (%d)!", result);
|
||||
}
|
||||
|
||||
#ifdef BSP_QSPI_USING_DMA
|
||||
/* QSPI interrupts must be enabled when using the HAL_QSPI_Receive_DMA */
|
||||
HAL_NVIC_SetPriority(QSPI_IRQn, 0, 0);
|
||||
HAL_NVIC_EnableIRQ(QSPI_IRQn);
|
||||
HAL_NVIC_SetPriority(QSPI_DMA_IRQ, 0, 0);
|
||||
HAL_NVIC_EnableIRQ(QSPI_DMA_IRQ);
|
||||
|
||||
/* init QSPI DMA */
|
||||
if(QSPI_DMA_RCC == RCC_AHB1ENR_DMA1EN)
|
||||
{
|
||||
__HAL_RCC_DMA1_CLK_ENABLE();
|
||||
}
|
||||
else
|
||||
{
|
||||
__HAL_RCC_DMA2_CLK_ENABLE();
|
||||
}
|
||||
|
||||
HAL_DMA_DeInit(qspi_bus->QSPI_Handler.hdma);
|
||||
DMA_HandleTypeDef hdma_quadspi_config = QSPI_DMA_CONFIG;
|
||||
qspi_bus->hdma_quadspi = hdma_quadspi_config;
|
||||
|
||||
if (HAL_DMA_Init(&qspi_bus->hdma_quadspi) != HAL_OK)
|
||||
{
|
||||
LOG_E("qspi dma init failed (%d)!", result);
|
||||
}
|
||||
|
||||
__HAL_LINKDMA(&qspi_bus->QSPI_Handler, hdma, qspi_bus->hdma_quadspi);
|
||||
#endif /* BSP_QSPI_USING_DMA */
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void qspi_send_cmd(struct stm32_qspi_bus *qspi_bus, struct rt_qspi_message *message)
|
||||
{
|
||||
RT_ASSERT(qspi_bus != RT_NULL);
|
||||
RT_ASSERT(message != RT_NULL);
|
||||
|
||||
QSPI_CommandTypeDef Cmdhandler;
|
||||
|
||||
/* set QSPI cmd struct */
|
||||
Cmdhandler.Instruction = message->instruction.content;
|
||||
Cmdhandler.Address = message->address.content;
|
||||
Cmdhandler.DummyCycles = message->dummy_cycles;
|
||||
if (message->instruction.qspi_lines == 0)
|
||||
{
|
||||
Cmdhandler.InstructionMode = QSPI_INSTRUCTION_NONE;
|
||||
}
|
||||
else if (message->instruction.qspi_lines == 1)
|
||||
{
|
||||
Cmdhandler.InstructionMode = QSPI_INSTRUCTION_1_LINE;
|
||||
}
|
||||
else if (message->instruction.qspi_lines == 2)
|
||||
{
|
||||
Cmdhandler.InstructionMode = QSPI_INSTRUCTION_2_LINES;
|
||||
}
|
||||
else if (message->instruction.qspi_lines == 4)
|
||||
{
|
||||
Cmdhandler.InstructionMode = QSPI_INSTRUCTION_4_LINES;
|
||||
}
|
||||
if (message->address.qspi_lines == 0)
|
||||
{
|
||||
Cmdhandler.AddressMode = QSPI_ADDRESS_NONE;
|
||||
}
|
||||
else if (message->address.qspi_lines == 1)
|
||||
{
|
||||
Cmdhandler.AddressMode = QSPI_ADDRESS_1_LINE;
|
||||
}
|
||||
else if (message->address.qspi_lines == 2)
|
||||
{
|
||||
Cmdhandler.AddressMode = QSPI_ADDRESS_2_LINES;
|
||||
}
|
||||
else if (message->address.qspi_lines == 4)
|
||||
{
|
||||
Cmdhandler.AddressMode = QSPI_ADDRESS_4_LINES;
|
||||
}
|
||||
if (message->address.size == 24)
|
||||
{
|
||||
Cmdhandler.AddressSize = QSPI_ADDRESS_24_BITS;
|
||||
}
|
||||
else
|
||||
{
|
||||
Cmdhandler.AddressSize = QSPI_ADDRESS_32_BITS;
|
||||
}
|
||||
if (message->qspi_data_lines == 0)
|
||||
{
|
||||
Cmdhandler.DataMode = QSPI_DATA_NONE;
|
||||
}
|
||||
else if (message->qspi_data_lines == 1)
|
||||
{
|
||||
Cmdhandler.DataMode = QSPI_DATA_1_LINE;
|
||||
}
|
||||
else if (message->qspi_data_lines == 2)
|
||||
{
|
||||
Cmdhandler.DataMode = QSPI_DATA_2_LINES;
|
||||
}
|
||||
else if (message->qspi_data_lines == 4)
|
||||
{
|
||||
Cmdhandler.DataMode = QSPI_DATA_4_LINES;
|
||||
}
|
||||
|
||||
Cmdhandler.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
|
||||
Cmdhandler.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
|
||||
Cmdhandler.DdrMode = QSPI_DDR_MODE_DISABLE;
|
||||
Cmdhandler.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
|
||||
Cmdhandler.NbData = message->parent.length;
|
||||
HAL_QSPI_Command(&qspi_bus->QSPI_Handler, &Cmdhandler, 5000);
|
||||
}
|
||||
|
||||
static rt_ssize_t qspixfer(struct rt_spi_device *device, struct rt_spi_message *message)
|
||||
{
|
||||
rt_ssize_t result = 0;
|
||||
|
||||
RT_ASSERT(device != RT_NULL);
|
||||
RT_ASSERT(device->bus != RT_NULL);
|
||||
|
||||
struct rt_qspi_message *qspi_message = (struct rt_qspi_message *)message;
|
||||
struct stm32_qspi_bus *qspi_bus = device->bus->parent.user_data;
|
||||
|
||||
const rt_uint8_t *sndb = message->send_buf;
|
||||
rt_uint8_t *rcvb = message->recv_buf;
|
||||
rt_int32_t length = message->length;
|
||||
|
||||
#ifdef BSP_QSPI_USING_SOFTCS
|
||||
if (message->cs_take && (device->cs_pin != PIN_NONE))
|
||||
{
|
||||
rt_pin_write(device->cs_pin, PIN_LOW);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* send data */
|
||||
if (sndb)
|
||||
{
|
||||
qspi_send_cmd(qspi_bus, qspi_message);
|
||||
if (qspi_message->parent.length != 0)
|
||||
{
|
||||
if (HAL_QSPI_Transmit(&qspi_bus->QSPI_Handler, (rt_uint8_t *)sndb, 5000) == HAL_OK)
|
||||
{
|
||||
result = length;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_E("QSPI send data failed(%d)!", qspi_bus->QSPI_Handler.ErrorCode);
|
||||
qspi_bus->QSPI_Handler.State = HAL_QSPI_STATE_READY;
|
||||
result = -RT_ERROR;
|
||||
goto __exit;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result = 1;
|
||||
}
|
||||
}
|
||||
else if (rcvb)/* recv data */
|
||||
{
|
||||
qspi_send_cmd(qspi_bus, qspi_message);
|
||||
#ifdef BSP_QSPI_USING_DMA
|
||||
if (HAL_QSPI_Receive_DMA(&qspi_bus->QSPI_Handler, rcvb) == HAL_OK)
|
||||
#else
|
||||
if (HAL_QSPI_Receive(&qspi_bus->QSPI_Handler, rcvb, 5000) == HAL_OK)
|
||||
#endif
|
||||
{
|
||||
result = length;
|
||||
#ifdef BSP_QSPI_USING_DMA
|
||||
while (qspi_bus->QSPI_Handler.RxXferCount != 0);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_E("QSPI recv data failed(%d)!", qspi_bus->QSPI_Handler.ErrorCode);
|
||||
qspi_bus->QSPI_Handler.State = HAL_QSPI_STATE_READY;
|
||||
result = -RT_ERROR;
|
||||
goto __exit;
|
||||
}
|
||||
}
|
||||
|
||||
__exit:
|
||||
#ifdef BSP_QSPI_USING_SOFTCS
|
||||
if (message->cs_release && (device->cs_pin != PIN_NONE))
|
||||
{
|
||||
rt_pin_write(device->cs_pin, PIN_HIGH);
|
||||
}
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
static rt_err_t qspi_configure(struct rt_spi_device *device, struct rt_spi_configuration *configuration)
|
||||
{
|
||||
RT_ASSERT(device != RT_NULL);
|
||||
RT_ASSERT(configuration != RT_NULL);
|
||||
|
||||
struct rt_qspi_device *qspi_device = (struct rt_qspi_device *)device;
|
||||
return stm32_qspi_init(qspi_device, &qspi_device->config);
|
||||
}
|
||||
|
||||
static const struct rt_spi_ops stm32_qspi_ops =
|
||||
{
|
||||
.configure = qspi_configure,
|
||||
.xfer = qspixfer,
|
||||
};
|
||||
|
||||
static int stm32_qspi_register_bus(struct stm32_qspi_bus *qspi_bus, const char *name)
|
||||
{
|
||||
RT_ASSERT(qspi_bus != RT_NULL);
|
||||
RT_ASSERT(name != RT_NULL);
|
||||
|
||||
_qspi_bus1.parent.user_data = qspi_bus;
|
||||
return rt_qspi_bus_register(&_qspi_bus1, name, &stm32_qspi_ops);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function attach device to QSPI bus.
|
||||
* @param device_name QSPI device name
|
||||
* @param cs_pin QSPI cs pin number
|
||||
* @param data_line_width QSPI data lines width, such as 1, 2, 4
|
||||
* @param enter_qspi_mode Callback function that lets FLASH enter QSPI mode
|
||||
* @param exit_qspi_mode Callback function that lets FLASH exit QSPI mode
|
||||
* @retval 0 : success
|
||||
* -1 : failed
|
||||
*/
|
||||
rt_err_t rt_hw_qspi_device_attach(const char *bus_name, const char *device_name, rt_base_t cs_pin, rt_uint8_t data_line_width, void (*enter_qspi_mode)(), void (*exit_qspi_mode)())
|
||||
{
|
||||
struct rt_qspi_device *qspi_device = RT_NULL;
|
||||
rt_err_t result = RT_EOK;
|
||||
|
||||
RT_ASSERT(bus_name != RT_NULL);
|
||||
RT_ASSERT(device_name != RT_NULL);
|
||||
RT_ASSERT(data_line_width == 1 || data_line_width == 2 || data_line_width == 4);
|
||||
|
||||
qspi_device = (struct rt_qspi_device *)rt_malloc(sizeof(struct rt_qspi_device));
|
||||
if (qspi_device == RT_NULL)
|
||||
{
|
||||
LOG_E("no memory, qspi bus attach device failed!");
|
||||
result = -RT_ENOMEM;
|
||||
goto __exit;
|
||||
}
|
||||
|
||||
qspi_device->enter_qspi_mode = enter_qspi_mode;
|
||||
qspi_device->exit_qspi_mode = exit_qspi_mode;
|
||||
qspi_device->config.qspi_dl_width = data_line_width;
|
||||
|
||||
#ifdef BSP_QSPI_USING_SOFTCS
|
||||
result = rt_spi_bus_attach_device_cspin(&qspi_device->parent, device_name, bus_name, cs_pin, RT_NULL);
|
||||
#else
|
||||
result = rt_spi_bus_attach_device_cspin(&qspi_device->parent, device_name, bus_name, PIN_NONE, RT_NULL);
|
||||
#endif /* BSP_QSPI_USING_SOFTCS */
|
||||
|
||||
__exit:
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
if (qspi_device)
|
||||
{
|
||||
rt_free(qspi_device);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef BSP_QSPI_USING_DMA
|
||||
void QSPI_IRQHandler(void)
|
||||
{
|
||||
/* enter interrupt */
|
||||
rt_interrupt_enter();
|
||||
|
||||
HAL_QSPI_IRQHandler(&_stm32_qspi_bus.QSPI_Handler);
|
||||
|
||||
/* leave interrupt */
|
||||
rt_interrupt_leave();
|
||||
}
|
||||
|
||||
void QSPI_DMA_IRQHandler(void)
|
||||
{
|
||||
/* enter interrupt */
|
||||
rt_interrupt_enter();
|
||||
|
||||
HAL_DMA_IRQHandler(&_stm32_qspi_bus.hdma_quadspi);
|
||||
|
||||
/* leave interrupt */
|
||||
rt_interrupt_leave();
|
||||
}
|
||||
#endif /* BSP_QSPI_USING_DMA */
|
||||
|
||||
static int rt_hw_qspi_bus_init(void)
|
||||
{
|
||||
return stm32_qspi_register_bus(&_stm32_qspi_bus, "qspi1");
|
||||
}
|
||||
INIT_BOARD_EXPORT(rt_hw_qspi_bus_init);
|
||||
|
||||
#endif /* BSP_USING_QSPI */
|
||||
#endif /* RT_USING_QSPI */
|
||||
Reference in New Issue
Block a user