Custom Driver Initialization Issues #73294
-
Hello, I am fairly new to Zephyr, and have been attempting to write a custom QSPI driver for a Nucelo-WB55RG development board (STM32) to interface with a couple external ADCs. The specific details regard ADC interfacing are not important; what I have been mainly struggling with is the basic zephyr device initialization using the driver. I modeled my code based on the existing qspi_stm32 flash driver and the basic pwm driver to understand how the initialization and api exposure process should work, but I am still running into issues with the pin control during init. I have pasted the build output and relevant code sections below. I apologize for dumping everything here, but I have been banging my head on the wall with this for a while and am not sure what is relevant. Thanks so much in advance for everyone's help! The main errors I have gotten from the build output are as follows:
From what I understand about how drivers work, driver instances are created upon initialization from the
This code block should create configuration and data structures for each instance, define the pin control for each instance, and bind the api and structures to the instance with Based on the build output, it seems like there is some issue with the instantiation of the pinctrl driver for each qspi instance (of which there should only be 1), but I can't really figure out what is going on based on the errors. For reference, node 71 refers to the qspi node. Here is the full custom driver code (cad_stm32_qspi.c): #define DT_DRV_COMPAT cad_stm32_qspi
#include <zephyr/kernel.h>
#include <zephyr/toolchain.h>
#include <zephyr/arch/common/ffs.h>
#include <zephyr/sys/util.h>
#include <soc.h>
#include <zephyr/sys/printk.h>
#include <zephyr/device.h>
#include <string.h>
#include <zephyr/drivers/dma.h>
#include <zephyr/drivers/dma/dma_stm32.h>
#include <stm32_ll_dma.h>
#include <zephyr/drivers/pinctrl.h>
#include <zephyr/drivers/clock_control/stm32_clock_control.h>
#include <zephyr/drivers/clock_control.h>
#include <zephyr/drivers/gpio.h>
#include "cad_qspi.h"
static void qspi_dma_callback(const struct device *dev, void *arg,
uint32_t channel, int status);
/* Necessary structures and defines */
#define STM32_QSPI_NODE(index) DT_DRV_INST(index)
//PINCTRL_DT_DEFINE(STM32_QSPI_NODE);
#define STM32_QSPI_FIFO_THRESHOLD 8
#define STM32_QSPI_USE_DMA DT_NODE_HAS_PROP(DT_DRV_INST(0), dmas)
#define DMA_CHANNEL_CONFIG(node, dir) DT_DMAS_CELL_BY_NAME(node, dir, channel_config)
#define QSPI_DMA_CHANNEL_INIT(node, dir) \
.dev = DEVICE_DT_GET(DT_DMAS_CTLR(node)), \
.channel = DT_DMAS_CELL_BY_NAME(node, dir, channel), \
.reg = (DMA_TypeDef *)DT_REG_ADDR( \
DT_PHANDLE_BY_NAME(node, dmas, dir)),\
.cfg = { \
.dma_slot = DT_DMAS_CELL_BY_NAME(node, dir, slot), \
.source_data_size = STM32_DMA_CONFIG_PERIPHERAL_DATA_SIZE( \
DMA_CHANNEL_CONFIG(node, dir)), \
.dest_data_size = STM32_DMA_CONFIG_MEMORY_DATA_SIZE( \
DMA_CHANNEL_CONFIG(node, dir)), \
.channel_priority = STM32_DMA_CONFIG_PRIORITY( \
DMA_CHANNEL_CONFIG(node, dir)), \
.dma_callback = qspi_dma_callback, \
}, \
#define QSPI_DMA_CHANNEL(node, dir) \
.dma = { \
COND_CODE_1(DT_DMAS_HAS_NAME(node, dir), \
(QSPI_DMA_CHANNEL_INIT(node, dir)), \
(NULL)) \
},
struct cad_qspi_config {
QUADSPI_TypeDef *regs;
struct stm32_pclken pclken;
const struct pinctrl_dev_config *pcfg;
};
struct stream {
DMA_TypeDef *reg;
const struct device *dev;
uint32_t channel;
struct dma_config cfg;
};
#if STM32_QSPI_USE_DMA
static const uint32_t table_m_size[] = {
LL_DMA_MDATAALIGN_BYTE,
LL_DMA_MDATAALIGN_HALFWORD,
LL_DMA_MDATAALIGN_WORD,
};
static const uint32_t table_p_size[] = {
LL_DMA_PDATAALIGN_BYTE,
LL_DMA_PDATAALIGN_HALFWORD,
LL_DMA_PDATAALIGN_WORD,
};
/* Lookup table to set dma priority from the DTS */
static const uint32_t table_priority[] = {
DMA_PRIORITY_LOW,
DMA_PRIORITY_MEDIUM,
DMA_PRIORITY_HIGH,
DMA_PRIORITY_VERY_HIGH,
};
#endif
struct cad_qspi_data {
QSPI_HandleTypeDef hqspi;
int cmd_status;
uint8_t qspi_read_cmd;
struct stream dma;
};
/* Exposed Functions */
static int cad_qspi_read(const struct device *dev, void *data, size_t size){
/*HAL_StatusTypeDef hal_ret;
struct cad_qspi_data *dev_data = (dev->data);
QSPI_CommandTypeDef cmd = {
.InstructionMode = 0,
.AddressMode = 0,
.AlternateByteMode = 0,
.DataMode = QSPI_DATA_2_LINES,
};
cmd.NbData = size;
dev_data->cmd_status = 0;
data = (uint8_t*)data;
#if STM32_QSPI_USE_DMA
hal_ret = HAL_QSPI_Receive_DMA(&dev_data->hqspi, data);
#else
hal_ret = HAL_QSPI_Receive_IT(&dev_data->hqspi, data);
#endif*/
//return dev_data->cmd_status;
return 1;
}
/* End Exposed Functions */
/* Internal Functions*/
static int cad_qspi_init(const struct device *dev)
{
const struct cad_qspi_config *dev_cfg = dev->config;
struct cad_qspi_data *dev_data = dev->data;
//uint32_t ahb_clock_freq;
uint32_t prescaler = 0;
int ret;
/* Signals configuration */
ret = pinctrl_apply_state(dev_cfg->pcfg, PINCTRL_STATE_DEFAULT);
#if STM32_QSPI_USE_DMA
struct dma_config dma_cfg = dev_data->dma.cfg; // Create configuration structure
static DMA_HandleTypeDef hdma; // From DMA HAL
dma_cfg.user_data = &hdma;
dma_cfg.linked_channel = STM32_DMA_HAL_OVERRIDE;
ret = dma_config(dev_data->dma.dev, dev_data->dma.channel, &dma_cfg);
/*if (dma_cfg.source_data_size != dma_cfg.dest_data_size) {
LOG_ERR("Source and destination data sizes not aligned");
return -EINVAL;
}*/
int index = find_lsb_set(dma_cfg.source_data_size) - 1;
hdma.Init.PeriphDataAlignment = table_p_size[index];
hdma.Init.MemDataAlignment = table_m_size[index];
hdma.Init.PeriphInc = DMA_PINC_DISABLE;
hdma.Init.MemInc = DMA_MINC_ENABLE;
hdma.Init.Mode = DMA_CIRCULAR;
hdma.Init.Priority = table_priority[dma_cfg.channel_priority];
hdma.Init.Request = dma_cfg.dma_slot;
#ifdef CONFIG_DMAMUX_STM32
/* HAL expects a valid DMA channel (not a DMAMUX channel) */
hdma.Instance = __LL_DMA_GET_CHANNEL_INSTANCE(dev_data->dma.reg,
dev_data->dma.channel);
#else
hdma.Instance = __LL_DMA_GET_CHANNEL_INSTANCE(dev_data->dma.reg,
dev_data->dma.channel-1);
#endif
__HAL_LINKDMA(&dev_data->hqspi, hdma, hdma);
HAL_DMA_Init(&hdma);
#endif
/* Initialize QSPI HAL */
dev_data->hqspi.Init.ClockPrescaler = prescaler;
HAL_QSPI_Init(&dev_data->hqspi);
return 0;
}
/* End Internal Functions*/
/* API Exposure and Routing*/
static const struct cad_qspi_driver_api stm32_qspi_driver_api = {
.read = cad_qspi_read,
};
#define QSPI_DEVICE_INIT(index) \
static struct cad_qspi_data cad_qspi_dev_data_##index = { \
.hqspi = { \
.Instance = (QUADSPI_TypeDef *)DT_REG_ADDR(STM32_QSPI_NODE(index)), \
.Init = { \
.FifoThreshold = STM32_QSPI_FIFO_THRESHOLD, \
.SampleShifting = QSPI_SAMPLE_SHIFTING_NONE, \
.ChipSelectHighTime = QSPI_CS_HIGH_TIME_1_CYCLE, \
.ClockMode = QSPI_CLOCK_MODE_0, \
}, \
}, \
QSPI_DMA_CHANNEL(STM32_QSPI_NODE(index), rx) \
}; \
PINCTRL_DT_INST_DEFINE(STM32_QSPI_NODE(index)); \
static const struct cad_qspi_config cad_qspi_cfg_##index = { \
.regs = (QUADSPI_TypeDef *)DT_REG_ADDR(STM32_QSPI_NODE(index)), \
.pclken = { \
.enr = DT_CLOCKS_CELL(STM32_QSPI_NODE(index), bits), \
.bus = DT_CLOCKS_CELL(STM32_QSPI_NODE(index), bus), \
}, \
.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(index), \
}; \
\
\
DEVICE_DT_INST_DEFINE(index, &cad_qspi_init, NULL, \
&cad_qspi_dev_data_##index, &cad_qspi_cfg_##index, \
POST_KERNEL, CONFIG_FLASH_INIT_PRIORITY, &stm32_qspi_driver_api);
// Initialize each active device
DT_INST_FOREACH_STATUS_OKAY(QSPI_DEVICE_INIT)
/* End API Exposure and Routing */
/* Callback Functions */
#if STM32_QSPI_USE_DMA
static void qspi_dma_callback(const struct device *dev, void *arg,
uint32_t channel, int status)
{
DMA_HandleTypeDef *hdma = arg;
//ARG_UNUSED(dev);
/*if (status < 0) {
LOG_ERR("DMA callback error with channel %d.", channel);
}*/
//HAL_DMA_IRQHandler(hdma);
}
#endif and header file (cad_qspi.h): #ifndef ZEPHYR_INCLUDE_DRIVERS_CAD_QSPI_H_
#define ZEPHYR_INCLUDE_DRIVERS_CAD_QSPI_H_
#include <zephyr/kernel.h>
#include <zephyr/device.h>
//typedef void (*irq_config_func_t)(const struct device *dev);
//static void flash_stm32_qspi_irq_config_func(const struct device *dev);
//#define CAD_QSPI_STM32_EXPORT_API static
typedef int (*cad_qspi_api_read)(const struct device *dev, void *data, size_t len);
static void qspi_dma_callback(const struct device *, void *, uint32_t, int);
__subsystem struct cad_qspi_driver_api {
cad_qspi_api_read read;
};
static inline int qspi_read(const struct device *dev, void *data, size_t len)
{
struct cad_qspi_driver_api *api = (struct cad_qspi_driver_api *)dev->api;
//printf("%x", (unsigned int)dev);
//return api->read(dev, data, len);
return 1;
}
#endif /* ZEPHYR_INCLUDE_DRIVERS_CAD_QSPI_H_ */
Relevant device tree nodes from build/zephyr.dts: quadspi: quadspi@a0001000 {
compatible = "cad,stm32-qspi";
#address-cells = < 0x1 >;
#size-cells = < 0x0 >;
reg = < 0xa0001000 0x400 >;
interrupts = < 0x32 0x0 >;
clocks = < &rcc 0x50 0x100 >;
status = "okay";
pinctrl-0 = < &quadspi_clk_pb10 &quadspi_bk1_ncs_pb11 &quadspi_bk1_io0_pb9 &quadspi_bk1_io1_pb8 &quadspi_bk1_io2_pa7 &quadspi_bk1_io3_pa6 >;
pinctrl-names = "default";
};
quadspi_bk1_io3_pa6: quadspi_bk1_io3_pa6 {
pinmux = < 0xca >;
slew-rate = "very-high-speed";
phandle = < 0x1f >;
};
quadspi_bk1_io2_pa7: quadspi_bk1_io2_pa7 {
pinmux = < 0xea >;
slew-rate = "very-high-speed";
phandle = < 0x1e >;
};
quadspi_bk1_io1_pb8: quadspi_bk1_io1_pb8 {
pinmux = < 0x30a >;
slew-rate = "very-high-speed";
phandle = < 0x1d >;
};
quadspi_bk1_io0_pb9: quadspi_bk1_io0_pb9 {
pinmux = < 0x32a >;
slew-rate = "very-high-speed";
phandle = < 0x1c >;
};
quadspi_clk_pb10: quadspi_clk_pb10 {
pinmux = < 0x34a >;
slew-rate = "very-high-speed";
phandle = < 0x1a >;
};
quadspi_bk1_ncs_pb11: quadspi_bk1_ncs_pb11 {
pinmux = < 0x36a >;
slew-rate = "very-high-speed";
phandle = < 0x1b >;
}; Compatible cad_stm32_qspi.yaml description: |
CAD custom STM32 QSPI device representation.
compatible: "cad,stm32-qspi"
include: [base.yaml, pinctrl-device.yaml]
bus: qspi
properties:
reg:
required: true
interrupts:
required: true
pinctrl-0:
required: true
pinctrl-names:
required: true
dmas:
dma-names:
description: |
DMA channel name. If DMA should be used, expected value is "rx".
For example
dma-names = "rx"; |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 3 replies
-
So in an embarrassing but fortunate situation, I ended up solving this particular pin control issue by changing the
#include <stdio.h>
#include <zephyr/kernel.h>
#include <zephyr/sys/printk.h>
#include <zephyr/drivers/clock_control.h>
#include <zephyr/logging/log.h>
#include <zephyr/device.h>
#include "../drivers/cad_qspi/cad_qspi.h"
#include <zephyr/devicetree.h>
#define QSPIINSTANCE DT_ALIAS(my_qspi)
static const struct device* qspi = DEVICE_DT_GET(QSPIINSTANCE); /* Gets a device structure from the device tree node*/
int main(void)
{
uint16_t rx_data;
while(1){
qspi_read(qspi, &rx_data, 16);
k_msleep(1000);
}
return 0;
} |
Beta Was this translation helpful? Give feedback.
-
@Delequesce To get the clue, you may search |
Beta Was this translation helpful? Give feedback.
Then please take a look at
build.ninja
to see ifcad_stm32_qspi.c
is included for compilation.I hope you have already added this file to your workspace's
CMakeLists.txt
.