1 /*
2  * Copyright (c) 2006-2024 RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2024-10-08     wumingzi      first implementation
9  * 2024-10-08     wumingzi      add custom configuration and support muti spi obj
10  */
11 
12 #include <rtthread.h>
13 #include <rtdevice.h>
14 #include <time.h>
15 
16 #include "rtdef.h"
17 #include "rttypes.h"
18 #include "sdkconfig.h"
19 
20 #include "hal/spi_hal.h" /*bsp/ESP32_C3/packages/ESP-IDF-latest/components/hal/include/hal/spi_types.h*/
21 #include "driver/gpio.h" /*bsp/ESP32_C3/packages/ESP-IDF-latest/components/driver/include/driver/gpio.h*/
22 #include "driver/spi_master.h"
23 
24 #include "drv_spi.h"
25 #include "drivers/dev_spi.h"
26 
27 #ifdef RT_USING_SPI
28 #ifdef BSP_USING_SPI2
29 #define LOG_TAG     "drv.spi"
30 #include <rtdbg.h>
31 
32 static struct rt_spi_bus spi_bus2;
33 
34 static spi_device_handle_t spi;
35 static spi_bus_config_t buscfg;
36 
37 static struct esp32_spi spi_bus_obj[] = {
38 #ifdef BSP_USING_SPI2
39     {
40         .bus_name = "spi2",
41         .spi_bus = &spi_bus2,
42         .esp32_spi_bus_cfg = &buscfg,
43     },
44 #endif /* BSP_USING_SPI2 */
45 };
46 
47 /* private rt-thread spi ops function */
48 static rt_err_t spi_configure(struct rt_spi_device* device, struct rt_spi_configuration* configuration);
49 static rt_ssize_t spixfer(struct rt_spi_device* device, struct rt_spi_message* message);
50 
51 static struct rt_spi_ops esp32_spi_ops =
52 {
53     .configure = spi_configure,
54     .xfer = spixfer,
55 };
56 
57 /**
58 * @brief SPI Initialization
59 * @param esp32_spi: SPI BUS
60 * @retval None
61 */
esp32_spi_init(struct esp32_spi * esp32_spi)62 static void esp32_spi_init(struct esp32_spi *esp32_spi)
63 {
64     spi_configure(NULL,NULL);
65 }
66 
spi_configure(struct rt_spi_device * device,struct rt_spi_configuration * configuration)67 static rt_err_t spi_configure(struct rt_spi_device* device,
68                           struct rt_spi_configuration* configuration)
69 {
70     static spi_bus_config_t buscfg =
71     {
72         .miso_io_num=SPI2_IOMUX_PIN_NUM_MISO,              /*MISO*/
73         .mosi_io_num=SPI2_IOMUX_PIN_NUM_MOSI,              /*MOSI*/
74         .sclk_io_num=SPI2_IOMUX_PIN_NUM_CLK,               /*CLK*/
75         .quadwp_io_num=-1,                      /*不使用*/
76         .quadhd_io_num=-1,                      /*不使用*/
77         .max_transfer_sz=4092                    /*最大传送数据长度*/
78     };
79 
80     esp_err_t err = spi_bus_initialize(SPI2_HOST, &buscfg, SPI_DMA_CH_AUTO);
81     ESP_ERROR_CHECK(err);
82 
83     static spi_device_interface_config_t devcfg;
84     if(configuration->data_width == 8)
85     {
86         size_t length;                  /*/< Total data length, in bits*/
87         size_t rxlength;                /*/< Total data length received, should be not greater than ``length`` in full-duplex mode (0 defaults this to the value of ``length``)*/
88     }
89 
90     LOG_W("configuration->max_hz = %d \n",configuration->max_hz);
91     if(configuration->max_hz >= SPI_MASTER_FREQ_80M)
92     {
93         devcfg.clock_speed_hz = SPI_MASTER_FREQ_80M;    /*/< 80MHz*/
94     }
95     else if(configuration->max_hz >= SPI_MASTER_FREQ_40M)
96     {
97         devcfg.clock_speed_hz = SPI_MASTER_FREQ_40M;    /*/< 40MHz*/
98     }
99     else if(configuration->max_hz >= SPI_MASTER_FREQ_26M)
100     {
101         devcfg.clock_speed_hz = SPI_MASTER_FREQ_26M;    /*/< 26.67MHz*/
102     }
103     else if(configuration->max_hz >= SPI_MASTER_FREQ_20M)
104     {
105         devcfg.clock_speed_hz = SPI_MASTER_FREQ_20M;    /*/< 20MHz*/
106     }
107     else if(configuration->max_hz >= SPI_MASTER_FREQ_16M)
108     {
109         devcfg.clock_speed_hz = SPI_MASTER_FREQ_16M;    /*/< 16MHz*/
110     }
111     else if(configuration->max_hz >= SPI_MASTER_FREQ_13M)
112     {
113         devcfg.clock_speed_hz = SPI_MASTER_FREQ_13M;    /*/< 13.33MHz*/
114     }
115     else if(configuration->max_hz >= SPI_MASTER_FREQ_11M)
116     {
117         devcfg.clock_speed_hz = SPI_MASTER_FREQ_11M;    /*/< 11.43MHz*/
118     }
119     else if(configuration->max_hz >= SPI_MASTER_FREQ_10M)
120     {
121         devcfg.clock_speed_hz = SPI_MASTER_FREQ_10M;    /*/< 10MHz*/
122     }
123     else if(configuration->max_hz >= SPI_MASTER_FREQ_9M)
124     {
125         devcfg.clock_speed_hz = SPI_MASTER_FREQ_9M ;    /*/< 8.89MHz*/
126     }
127     else
128     {
129         devcfg.clock_speed_hz = SPI_MASTER_FREQ_8M ;
130     }
131 
132     switch (configuration->mode)
133     {
134         case RT_SPI_MODE_0: /*!< CPOL = 0, CPHA = 0 */
135             devcfg.mode = 0;
136         case RT_SPI_MODE_1: /*!< CPOL = 0, CPHA = 1 */
137             devcfg.mode = 1;
138         case RT_SPI_MODE_2: /*!< CPOL = 1, CPHA = 0 */
139             devcfg.mode = 2;
140         case RT_SPI_MODE_3: /*!< CPOL = 1, CPHA = 1 */
141             devcfg.mode = 3;
142         default:
143             devcfg.mode = 0;
144     }
145 
146     /* todo: support changing cs_pin,queue_size or specifing spi_device_interface_config_t and
147     * spi_transaction_t by resever data.Meanwhile finish the initialization of interrupt
148     * callback function and dma.
149     */
150 
151     devcfg.spics_io_num = RT_BSP_SPI_CS_PIN;
152     devcfg.queue_size = 7;
153 
154     err = spi_bus_add_device(SPI2_HOST, &devcfg, &spi);
155     ESP_ERROR_CHECK(err);
156 
157     /* Although there is only one spi bus object, it will be a template for other bsps of ESP32 series */
158     for(int i = 0; i < sizeof(spi_bus_obj)/sizeof(spi_bus_obj[0]); i++)
159     {
160         spi_bus_obj[i].bus_name = "spi2";
161         spi_bus_obj[i].spi_bus = &spi_bus2;
162         spi_bus_obj[i].esp32_spi_bus_cfg = &buscfg;
163     }
164 
165     return RT_EOK;
166 };
167 
spixfer(struct rt_spi_device * device,struct rt_spi_message * message)168 static rt_ssize_t spixfer(struct rt_spi_device* device, struct rt_spi_message* message)
169 {
170 
171     RT_ASSERT(device != NULL);
172     RT_ASSERT(message != NULL);
173 
174     static spi_transaction_t trans;
175 
176     trans.tx_buffer = message->send_buf;
177     trans.rx_buffer = message->recv_buf;
178     trans.length = (message->length)*8;
179     trans.rxlength = (message->length)*8;
180 
181     spi_device_acquire_bus(spi, portMAX_DELAY);
182     esp_err_t err = spi_device_polling_transmit(spi, &trans);
183 
184     spi_device_release_bus(spi);
185 
186     ESP_ERROR_CHECK(err);
187     return RT_EOK;
188 };
189 
190 /**
191   * Attach the spi device to SPI bus, this function must be used after initialization.
192   */
rt_hw_spi_device_attach(const char * bus_name,const char * device_name,rt_base_t cs_pin)193 rt_err_t rt_hw_spi_device_attach(const char *bus_name, const char *device_name, rt_base_t cs_pin)
194 {
195     RT_ASSERT(bus_name != RT_NULL);
196     RT_ASSERT(device_name != RT_NULL);
197 
198     rt_err_t result;rt_device_t busp = RT_NULL;
199     struct rt_spi_device *spi_device;
200 
201     /* attach the device to spi bus*/
202     spi_device = (struct rt_spi_device *)rt_malloc(sizeof(struct rt_spi_device));
203     RT_ASSERT(spi_device != RT_NULL);
204 
205     result = rt_spi_bus_attach_device(spi_device, device_name, bus_name, (void *)cs_pin);
206 
207     if (result != RT_EOK)
208     {
209         LOG_E("%s attach to %s faild, %d\n", device_name, bus_name, result);
210     }
211 
212     RT_ASSERT(result == RT_EOK);
213 
214     LOG_D("%s attach to %s done", device_name, bus_name);
215 
216     return result;
217 }
218 
rt_hw_spi_init(void)219 int rt_hw_spi_init(void)
220 {
221     int result = 0;
222 
223     for(int i = 0; i < sizeof(spi_bus_obj)/sizeof(spi_bus_obj[0]); i++)
224     {
225         spi_bus_obj[i].spi_bus->parent.user_data = (void *)&spi_bus_obj[i];
226         result = rt_spi_bus_register(spi_bus_obj[i].spi_bus, spi_bus_obj[i].bus_name, &esp32_spi_ops);
227 
228         RT_ASSERT(result == RT_EOK);
229 
230         LOG_D("%s bus init done", spi_bus_obj[i].bus_name);
231     }
232 
233     return result;
234 }
235 
236 INIT_BOARD_EXPORT(rt_hw_spi_init);
237 
238 #endif /* BSP_USING_SPI0 || BSP_USING_SPI1 || BSP_USING_SPI2 || BSP_USING_SPI3 || BSP_USING_SPI4*/
239 #endif /* RT_USING_SPI */