diff --git a/components/dfs/filesystems/elmfat/dfs_elm.c b/components/dfs/filesystems/elmfat/dfs_elm.c index 290cf7c4bb46ceeb876a96fdbaed6bedbbabc636..582333a714963891150762e91ace48f50666be86 100644 --- a/components/dfs/filesystems/elmfat/dfs_elm.c +++ b/components/dfs/filesystems/elmfat/dfs_elm.c @@ -265,7 +265,7 @@ int dfs_elm_mkfs(rt_device_t dev_id) /* [IN] Size of the allocation unit */ /* [-] Working buffer */ /* [IN] Size of working buffer */ - result = f_mkfs(logic_nbr, FM_ANY, 0, work, _MAX_SS); + result = f_mkfs(logic_nbr, FM_ANY|FM_SFD, 0, work, _MAX_SS); rt_free(work); work = RT_NULL; /* check flag status, we need clear the temp driver stored in disk[] */ diff --git a/components/dfs/src/dfs.c b/components/dfs/src/dfs.c index 38a1813421ead9cae1672b001997155290e53b8a..cf0b2b0ef99485bbe017d98e83e7d91e2724ce57 100644 --- a/components/dfs/src/dfs.c +++ b/components/dfs/src/dfs.c @@ -221,7 +221,7 @@ struct dfs_fd *fd_get(int fd) d = fdt->fds[fd]; /* check dfs_fd valid or not */ - if (d->magic != DFS_FD_MAGIC) + if ((d == NULL) || (d->magic != DFS_FD_MAGIC)) { dfs_unlock(); return NULL; diff --git a/components/dfs/src/dfs_posix.c b/components/dfs/src/dfs_posix.c index 97531ad59cf35f8d443e040cb316aedda179668a..f47a60ee5dc34da490b16155143b43f326205b90 100644 --- a/components/dfs/src/dfs_posix.c +++ b/components/dfs/src/dfs_posix.c @@ -890,9 +890,9 @@ int access(const char *path, int amode) char *getcwd(char *buf, size_t size) { #ifdef DFS_USING_WORKDIR - rt_enter_critical(); + dfs_lock(); strncpy(buf, working_directory, size); - rt_exit_critical(); + dfs_unlock(); #else rt_kprintf(NO_WORKING_DIR); #endif diff --git a/components/drivers/Kconfig b/components/drivers/Kconfig index 824b3e00da646f79dbc46d077e78c922cec963c8..d8dc5e74581600d4aa120032518e00d5849fa49e 100755 --- a/components/drivers/Kconfig +++ b/components/drivers/Kconfig @@ -16,6 +16,12 @@ config RT_USING_SERIAL select RT_USING_DEVICE default y +if RT_USING_SERIAL + config RT_SERIAL_USING_DMA + bool "Enable serial DMA mode" + default y +endif + config RT_USING_CAN bool "Using CAN device drivers" default n @@ -72,6 +78,10 @@ config RT_USING_PIN bool "Using generic GPIO device drivers" default y +config RT_USING_ADC + bool "Using ADC device drivers" + default n + config RT_USING_PWM bool "Using PWM device drivers" default n @@ -118,9 +128,8 @@ config RT_USING_RTC default n config RTC_SYNC_USING_NTP bool "Using NTP auto sync RTC time" - select PKG_USING_NETUTILS - select PKG_NETUTILS_NTP - default n + depends on PKG_NETUTILS_NTP + default y if RTC_SYNC_USING_NTP config RTC_NTP_FIRST_SYNC_DELAY @@ -165,7 +174,11 @@ config RT_USING_SPI bool "Using SPI Bus/Device device drivers" default n - if RT_USING_SPI + if RT_USING_SPI + config RT_USING_QSPI + bool "Enable QSPI mode" + default n + config RT_USING_SPI_MSD bool "Using SD/TF card driver with spi" select RT_USING_DFS @@ -182,6 +195,11 @@ config RT_USING_SPI config RT_SFUD_USING_FLASH_INFO_TABLE bool "Using defined supported flash chip information table" default y + + config RT_SFUD_USING_QSPI + bool "Using QSPI mode support" + select RT_USING_QSPI + default n config RT_DEBUG_SFUD bool "Show more SFUD debug information" diff --git a/components/drivers/audio/audio.c b/components/drivers/audio/audio.c index 14dddb38ea9803cdb3f1610c1af42dcb8f738f19..6a5ebc87415fcfae2ba586470c0ba9c94c11c506 100644 --- a/components/drivers/audio/audio.c +++ b/components/drivers/audio/audio.c @@ -105,8 +105,6 @@ static rt_err_t _audio_dev_init(struct rt_device *dev) static rt_err_t _audio_dev_open(struct rt_device *dev, rt_uint16_t oflag) { - rt_err_t result = RT_EOK; - rt_base_t level; struct rt_audio_device *audio; RT_ASSERT(dev != RT_NULL); @@ -159,7 +157,6 @@ static rt_err_t _audio_dev_open(struct rt_device *dev, rt_uint16_t oflag) //init pipe for record { - rt_size_t size = CFG_AUDIO_RECORD_PIPE_SIZE; rt_uint8_t *buf = rt_malloc(CFG_AUDIO_RECORD_PIPE_SIZE); if (buf == RT_NULL) @@ -170,7 +167,7 @@ static rt_err_t _audio_dev_open(struct rt_device *dev, rt_uint16_t oflag) return -RT_ENOMEM; } - rt_audio_pipe_init(&audio_pipe, "recpipe", RT_PIPE_FLAG_FORCE_WR | RT_PIPE_FLAG_BLOCK_RD, buf, + rt_audio_pipe_init(&audio_pipe, "recpipe", (rt_int32_t)(RT_PIPE_FLAG_FORCE_WR | RT_PIPE_FLAG_BLOCK_RD), buf, CFG_AUDIO_RECORD_PIPE_SIZE); } @@ -536,8 +533,6 @@ void rt_audio_tx_complete(struct rt_audio_device *audio, rt_uint8_t *pbuf) void rt_audio_rx_done(struct rt_audio_device *audio, rt_uint8_t *pbuf, rt_size_t len) { - rt_err_t result = RT_EOK; - //save data to record pipe rt_device_write(RT_DEVICE(RT_DEVICE(&audio_pipe)), 0, pbuf, len); diff --git a/components/drivers/audio/audio_pipe.c b/components/drivers/audio/audio_pipe.c index 242305e20457d50958f4f0484f6b84f1230df885..4df9fd8a49bba87b7ced38a5a3853653f12be717 100644 --- a/components/drivers/audio/audio_pipe.c +++ b/components/drivers/audio/audio_pipe.c @@ -188,7 +188,7 @@ static rt_err_t rt_pipe_control(rt_device_t dev, int cmd, void *args) } #ifdef RT_USING_DEVICE_OPS -const static struct rt_device_ops audio_pipe_ops +const static struct rt_device_ops audio_pipe_ops = { RT_NULL, RT_NULL, @@ -213,7 +213,7 @@ const static struct rt_device_ops audio_pipe_ops */ rt_err_t rt_audio_pipe_init(struct rt_audio_pipe *pipe, const char *name, - enum rt_audio_pipe_flag flag, + rt_int32_t flag, rt_uint8_t *buf, rt_size_t size) { @@ -258,7 +258,7 @@ rt_err_t rt_audio_pipe_detach(struct rt_audio_pipe *pipe) } #ifdef RT_USING_HEAP -rt_err_t rt_audio_pipe_create(const char *name, enum rt_audio_pipe_flag flag, rt_size_t size) +rt_err_t rt_audio_pipe_create(const char *name, rt_int32_t flag, rt_size_t size) { rt_uint8_t *rb_memptr = RT_NULL; struct rt_audio_pipe *pipe = RT_NULL; diff --git a/components/drivers/audio/audio_pipe.h b/components/drivers/audio/audio_pipe.h index c34f72b019b8fae467eb7453a27afdc8b06110ca..85a3eb17933f01aec601c482be63aaec6bc8b22c 100644 --- a/components/drivers/audio/audio_pipe.h +++ b/components/drivers/audio/audio_pipe.h @@ -50,7 +50,7 @@ struct rt_audio_pipe /* ring buffer in pipe device */ struct rt_ringbuffer ringbuffer; - enum rt_audio_pipe_flag flag; + rt_int32_t flag; /* suspended list */ rt_list_t suspended_read_list; @@ -64,12 +64,12 @@ struct rt_audio_pipe rt_err_t rt_audio_pipe_init(struct rt_audio_pipe *pipe, const char *name, - enum rt_audio_pipe_flag flag, + rt_int32_t flag, rt_uint8_t *buf, rt_size_t size); rt_err_t rt_audio_pipe_detach(struct rt_audio_pipe *pipe); #ifdef RT_USING_HEAP -rt_err_t rt_audio_pipe_create(const char *name, enum rt_audio_pipe_flag flag, rt_size_t size); +rt_err_t rt_audio_pipe_create(const char *name, rt_int32_t flag, rt_size_t size); void rt_audio_pipe_destroy(struct rt_audio_pipe *pipe); #endif #endif diff --git a/components/drivers/hwtimer/README_CN.md b/components/drivers/hwtimer/README_CN.md index fb3b4fa60a25b8a21e17448b73b2870d0f5dce43..810b1b1d80bff4d751ccaac916490234c16b44b8 100644 --- a/components/drivers/hwtimer/README_CN.md +++ b/components/drivers/hwtimer/README_CN.md @@ -1,17 +1,16 @@ -定时器设备 -=== - -##功能 ---- +# 定时器设备 + +## 功能 + * 时间测量 * 周期或单次执行回调函数 -##编译 ---- +## 编译 + 1. 在rtconfig.h添加 `#define RT_USING_HWTIMER` - -##使用流程 ---- + +## 使用流程 + 1. 以读写方式打开设备 2. 设置超时回调函数(如果需要) 3. 根据需要设置定时模式(单次/周期) @@ -19,12 +18,12 @@ 5. 写入超时值,定时器随即启动 6. 停止定时器(可选) 7. 关闭设备(如果需要) - + 应用参考 [hwtimer_test] (/examples/test/hwtimer\_test.c) -##驱动编写指南 ---- -###操作接口 +## 驱动编写指南 + +### 操作接口 ``` struct rt_hwtimer_ops @@ -43,8 +42,8 @@ struct rt_hwtimer_ops * count_get - <读取计数器值> * control - <设置计数频率 > -###定时器特征信息 - +### 定时器特征信息 + ``` struct rt_hwtimer_info { @@ -60,7 +59,8 @@ struct rt_hwtimer_info * maxcnt <计数器最大计数值> * cntmode <递增计数/递减计数> -###注册设备 +### 注册设备 + ``` static rt_hwtimer_t _timer0; int stm32_hwtimer_init(void) @@ -73,8 +73,9 @@ int stm32_hwtimer_init(void) return 0; } ``` - -###定时器中断 + +### 定时器中断 + ``` void timer_irq_handler(void) { @@ -84,15 +85,13 @@ void timer_irq_handler(void) } ``` -##注意事项 ---- - -可能出现定时误差 - +## 注意事项 + +**可能出现定时误差** 误差原因: 假设计数器最大值0xFFFF,计数频率1Mhz,定时时间1秒又1微秒。 - + 由于定时器一次最多只能计时到65535us,对于1000001us的定时要求。 可以50000us定时20次完成,此时将会出现计算误差1us。 diff --git a/components/drivers/hwtimer/hwtimer.c b/components/drivers/hwtimer/hwtimer.c index cd85b3baefca170b8278863bbaf90d7e83262d69..83a76c7b9d8e31dde95e47a8bfed576d8ebef2ab 100644 --- a/components/drivers/hwtimer/hwtimer.c +++ b/components/drivers/hwtimer/hwtimer.c @@ -153,7 +153,7 @@ static rt_size_t rt_hwtimer_read(struct rt_device *dev, rt_off_t pos, void *buff cnt = timer->ops->count_get(timer); if (timer->info->cntmode == HWTIMER_CNTMODE_DW) { - cnt = timer->info->maxcnt - cnt; + cnt = (timer->freq * timer->period_sec) - cnt; } t = timer->overflow * timer->period_sec + cnt/(float)timer->freq; diff --git a/components/drivers/include/drivers/adc.h b/components/drivers/include/drivers/adc.h new file mode 100644 index 0000000000000000000000000000000000000000..8e3498e7910f8e9d647291b9a8d9c6e58d74304e --- /dev/null +++ b/components/drivers/include/drivers/adc.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2006-2018, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2018-05-07 aozima the first version + * 2018-11-16 Ernest Chen add finsh command and update adc function + */ + +#ifndef __ADC_H__ +#define __ADC_H__ +#include + +struct rt_adc_device; +struct rt_adc_ops +{ + rt_err_t (*enabled)(struct rt_adc_device *device, rt_uint32_t channel, rt_bool_t enabled); + rt_err_t (*convert)(struct rt_adc_device *device, rt_uint32_t channel, rt_uint32_t *value); +}; + +struct rt_adc_device +{ + struct rt_device parent; + const struct rt_adc_ops *ops; +}; +typedef struct rt_adc_device *rt_adc_device_t; + +typedef enum +{ + RT_ADC_CMD_ENABLE, + RT_ADC_CMD_DISABLE, +} rt_adc_cmd_t; + +rt_err_t rt_hw_adc_register(rt_adc_device_t adc,const char *name, const struct rt_adc_ops *ops, const void *user_data); + +rt_uint32_t rt_adc_read(rt_adc_device_t dev, rt_uint32_t channel); +rt_err_t rt_adc_enable(rt_adc_device_t dev, rt_uint32_t channel); +rt_err_t rt_adc_disable(rt_adc_device_t dev, rt_uint32_t channel); + +#endif /* __ADC_H__ */ diff --git a/components/drivers/include/drivers/serial.h b/components/drivers/include/drivers/serial.h index af5d6262516875ef30f216d855d9b5f398290c03..45095af63f36f5749154fa1055731975804db884 100644 --- a/components/drivers/include/drivers/serial.h +++ b/components/drivers/include/drivers/serial.h @@ -100,7 +100,7 @@ struct serial_configure rt_uint32_t bit_order :1; rt_uint32_t invert :1; rt_uint32_t bufsz :16; - rt_uint32_t reserved :4; + rt_uint32_t reserved :6; }; /* diff --git a/components/drivers/include/drivers/spi.h b/components/drivers/include/drivers/spi.h index 84b589ace0f0efa91df34f7902bf28d398bf6224..04a65421a53cada4a3227e8f6a8f343f76452598 100644 --- a/components/drivers/include/drivers/spi.h +++ b/components/drivers/include/drivers/spi.h @@ -45,6 +45,9 @@ extern "C"{ #define RT_SPI_MODE_MASK (RT_SPI_CPHA | RT_SPI_CPOL | RT_SPI_MSB) +#define RT_SPI_BUS_MODE_SPI (1<<0) +#define RT_SPI_BUS_MODE_QSPI (1<<1) + #define RT_SPI_CS_HIGH (1<<4) /* Chipselect active high */ #define RT_SPI_NO_CS (1<<5) /* No chipselect */ #define RT_SPI_3WIRE (1<<6) /* SI/SO pin shared */ @@ -80,6 +83,7 @@ struct rt_spi_ops; struct rt_spi_bus { struct rt_device parent; + rt_uint8_t mode; const struct rt_spi_ops *ops; struct rt_mutex lock; @@ -106,6 +110,55 @@ struct rt_spi_device struct rt_spi_configuration config; void *user_data; }; + +struct rt_qspi_message +{ + struct rt_spi_message parent; + + /* instruction stage */ + struct + { + rt_uint8_t content; + rt_uint8_t qspi_lines; + } instruction; + + /* address and alternate_bytes stage */ + struct + { + rt_uint32_t content; + rt_uint8_t size; + rt_uint8_t qspi_lines; + } address, alternate_bytes; + + /* dummy_cycles stage */ + rt_uint32_t dummy_cycles; + + /* number of lines in qspi data stage, the other configuration items are in parent */ + rt_uint8_t qspi_data_lines; +}; + +struct rt_qspi_configuration +{ + struct rt_spi_configuration parent; + /* The size of medium */ + rt_uint32_t medium_size; + /* double data rate mode */ + rt_uint8_t ddr_mode; + /* the data lines max width which QSPI bus supported, such as 1, 2, 4 */ + rt_uint8_t qspi_dl_width ; +}; + +struct rt_qspi_device +{ + struct rt_spi_device parent; + + struct rt_qspi_configuration config; + + void (*enter_qspi_mode)(struct rt_qspi_device *device); + + void (*exit_qspi_mode)(struct rt_qspi_device *device); +}; + #define SPI_DEVICE(dev) ((struct rt_spi_device *)(dev)) /* register a SPI bus */ @@ -255,6 +308,61 @@ rt_inline void rt_spi_message_append(struct rt_spi_message *list, message->next = RT_NULL; } +/** + * This function can set configuration on QSPI device. + * + * @param device the QSPI device attached to QSPI bus. + * @param cfg the configuration pointer. + * + * @return the actual length of transmitted. + */ +rt_err_t rt_qspi_configure(struct rt_qspi_device *device, struct rt_qspi_configuration *cfg); + +/** + * This function can register a SPI bus for QSPI mode. + * + * @param bus the SPI bus for QSPI mode. + * @param name The name of the spi bus. + * @param ops the SPI bus instance to be registered. + * + * @return the actual length of transmitted. + */ +rt_err_t rt_qspi_bus_register(struct rt_spi_bus *bus, const char *name, const struct rt_spi_ops *ops); + +/** + * This function transmits data to QSPI device. + * + * @param device the QSPI device attached to QSPI bus. + * @param message the message pointer. + * + * @return the actual length of transmitted. + */ +rt_size_t rt_qspi_transfer_message(struct rt_qspi_device *device, struct rt_qspi_message *message); + +/** + * This function can send data then receive data from QSPI device + * + * @param device the QSPI device attached to QSPI bus. + * @param send_buf the buffer to be transmitted to QSPI device. + * @param send_length the number of data to be transmitted. + * @param recv_buf the buffer to be recivied from QSPI device. + * @param recv_length the data to be recivied. + * + * @return the status of transmit. + */ +rt_err_t rt_qspi_send_then_recv(struct rt_qspi_device *device, const void *send_buf, rt_size_t send_length,void *recv_buf, rt_size_t recv_length); + +/** + * This function can send data to QSPI device + * + * @param device the QSPI device attached to QSPI bus. + * @param send_buf the buffer to be transmitted to QSPI device. + * @param send_length the number of data to be transmitted. + * + * @return the status of transmit. + */ +rt_err_t rt_qspi_send(struct rt_qspi_device *device, const void *send_buf, rt_size_t length); + #ifdef __cplusplus } #endif diff --git a/components/drivers/include/ipc/ringblk_buf.h b/components/drivers/include/ipc/ringblk_buf.h index 653fa2a60bbd3323eb3f2615d21d625694ff4d54..94fc2cfff33c8fa96263197ee998a11aedc924a1 100644 --- a/components/drivers/include/ipc/ringblk_buf.h +++ b/components/drivers/include/ipc/ringblk_buf.h @@ -84,6 +84,8 @@ rt_size_t rt_rbb_get_buf_size(rt_rbb_t rbb); rt_rbb_blk_t rt_rbb_blk_alloc(rt_rbb_t rbb, rt_size_t blk_size); void rt_rbb_blk_put(rt_rbb_blk_t block); rt_rbb_blk_t rt_rbb_blk_get(rt_rbb_t rbb); +rt_size_t rt_rbb_blk_size(rt_rbb_blk_t block); +rt_uint8_t *rt_rbb_blk_buf(rt_rbb_blk_t block); void rt_rbb_blk_free(rt_rbb_t rbb, rt_rbb_blk_t block); /* rbb block queue API */ diff --git a/components/drivers/include/rtdevice.h b/components/drivers/include/rtdevice.h index 1843432768d944ba96b083fb1133c34384f3c89b..d59b40cc47d4e00d30e14509dec20765b45f26cb 100644 --- a/components/drivers/include/rtdevice.h +++ b/components/drivers/include/rtdevice.h @@ -99,6 +99,10 @@ extern "C" { #include "drivers/cputime.h" #endif +#ifdef RT_USING_ADC +#include "drivers/adc.h" +#endif + #ifdef RT_USING_PWM #include "drivers/rt_drv_pwm.h" #endif diff --git a/components/drivers/misc/SConscript b/components/drivers/misc/SConscript index 4cc5f80084c8ee2f938e87d240e5e89a488a6e79..c45ba524c5d2a1d2f79831d56402d3d526cd4abf 100644 --- a/components/drivers/misc/SConscript +++ b/components/drivers/misc/SConscript @@ -7,7 +7,10 @@ group = [] if GetDepend(['RT_USING_PIN']): src = src + ['pin.c'] - + +if GetDepend(['RT_USING_ADC']): + src = src + ['adc.c'] + if GetDepend(['RT_USING_PWM']): src = src + ['rt_drv_pwm.c'] diff --git a/components/drivers/misc/adc.c b/components/drivers/misc/adc.c new file mode 100644 index 0000000000000000000000000000000000000000..83e789a6e4271d004e80302c174522eba5f6ff68 --- /dev/null +++ b/components/drivers/misc/adc.c @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2006-2018, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2018-05-07 aozima the first version + * 2018-11-16 Ernest Chen add finsh command and update adc function + */ + +#include +#include + +#include +#include + +#define DBG_ENABLE +#define DBG_SECTION_NAME "adc" +#define DBG_LEVEL DBG_INFO +#define DBG_COLOR +#include + +static rt_size_t _adc_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size) +{ + rt_err_t result = RT_EOK; + rt_size_t i; + struct rt_adc_device *adc = (struct rt_adc_device *)dev; + rt_uint32_t *value = (rt_uint32_t *)buffer; + + for (i = 0; i < size; i += sizeof(int)) + { + result = adc->ops->convert(adc, pos + i, value); + if (result != RT_EOK) + { + return 0; + } + value++; + } + + return i; +} + +static rt_err_t _adc_control(rt_device_t dev, int cmd, void *args) +{ + rt_err_t result = RT_EOK; + rt_adc_device_t adc = (struct rt_adc_device *)dev; + + if (adc->ops->enabled == RT_NULL) + { + return -RT_ENOSYS; + } + if (cmd == RT_ADC_CMD_ENABLE) + { + result = adc->ops->enabled(adc, (rt_uint32_t)args, RT_TRUE); + } + else if (cmd == RT_ADC_CMD_DISABLE) + { + result = adc->ops->enabled(adc, (rt_uint32_t)args, RT_FALSE); + } + + return result; +} + +rt_err_t rt_hw_adc_register(rt_adc_device_t device, const char *name, const struct rt_adc_ops *ops, const void *user_data) +{ + rt_err_t result = RT_EOK; + RT_ASSERT(ops != RT_NULL && ops->convert != RT_NULL); + + device->parent.type = RT_Device_Class_Miscellaneous; + device->parent.init = RT_NULL; + device->parent.open = RT_NULL; + device->parent.close = RT_NULL; + device->parent.read = _adc_read; + device->parent.write = RT_NULL; + device->parent.control = _adc_control; + + device->ops = ops; + device->parent.user_data = (void *)user_data; + + result = rt_device_register(&device->parent, name, RT_DEVICE_FLAG_RDWR); + + return result; +} + +rt_uint32_t rt_adc_read(rt_adc_device_t dev, rt_uint32_t channel) +{ + rt_uint32_t value; + + RT_ASSERT(dev); + + dev->ops->convert(dev, channel, &value); + + return value; +} + +rt_err_t rt_adc_enable(rt_adc_device_t dev, rt_uint32_t channel) +{ + rt_err_t result = RT_EOK; + + RT_ASSERT(dev); + if (dev->ops->enabled != RT_NULL) + { + result = dev->ops->enabled(dev, channel, RT_TRUE); + } + else + { + result = -RT_ENOSYS; + } + + return result; +} + +rt_err_t rt_adc_disable(rt_adc_device_t dev, rt_uint32_t channel) +{ + rt_err_t result = RT_EOK; + + RT_ASSERT(dev); + if (dev->ops->enabled != RT_NULL) + { + result = dev->ops->enabled(dev, channel, RT_FALSE); + } + else + { + result = -RT_ENOSYS; + } + + return result; +} + +#ifdef FINSH_USING_MSH + +static int adc(int argc, char **argv) +{ + int value = 0; + int result = RT_EOK; + static rt_adc_device_t adc_device = RT_NULL; + char *result_str; + + if (argc > 1) + { + if (!strcmp(argv[1], "probe")) + { + if (argc == 3) + { + adc_device = (rt_adc_device_t)rt_device_find(argv[2]); + result_str = (adc_device == RT_NULL) ? "failure" : "success"; + rt_kprintf("probe %s %s \n", argv[2], result_str); + } + else + { + rt_kprintf("adc probe - probe adc by name\n"); + } + } + else + { + if (adc_device == RT_NULL) + { + rt_kprintf("Please using 'adc probe ' first\n"); + return -RT_ERROR; + } + if (!strcmp(argv[1], "enable")) + { + if (argc == 3) + { + result = rt_adc_enable(adc_device, atoi(argv[2])); + result_str = (result == RT_EOK) ? "success" : "failure"; + rt_kprintf("%s channel %d enables %s \n", adc_device->parent.parent.name, atoi(argv[2]), result_str); + } + else + { + rt_kprintf("adc enable - enable adc channel\n"); + } + } + else if (!strcmp(argv[1], "read")) + { + if (argc == 3) + { + value = rt_adc_read(adc_device, atoi(argv[2])); + rt_kprintf("%s channel %d read value is 0x%08X \n", adc_device->parent.parent.name, atoi(argv[2]), value); + } + else + { + rt_kprintf("adc read - read adc value on the channel\n"); + } + } + else if (!strcmp(argv[1], "disable")) + { + if (argc == 3) + { + result = rt_adc_disable(adc_device, atoi(argv[2])); + result_str = (result == RT_EOK) ? "success" : "failure"; + rt_kprintf("%s channel %d disable %s \n", adc_device->parent.parent.name, atoi(argv[2]), result_str); + } + else + { + rt_kprintf("adc disable - disable adc channel\n"); + } + } + else + { + rt_kprintf("Unknown command. Please enter 'adc' for help\n"); + } + } + } + else + { + rt_kprintf("Usage: \n"); + rt_kprintf("adc probe - probe adc by name\n"); + rt_kprintf("adc read - read adc value on the channel\n"); + rt_kprintf("adc disable - disable adc channel\n"); + rt_kprintf("adc enable - enable adc channel\n"); + result = -RT_ERROR; + } + return RT_EOK; +} +MSH_CMD_EXPORT(adc, adc function); + +#endif /* FINSH_USING_MSH */ diff --git a/components/drivers/misc/rt_drv_pwm.c b/components/drivers/misc/rt_drv_pwm.c index 6890e0e7932b72d926879708df2961b2d4e36cd4..2b7986b4d80ec371c4f2adc539c26ea9d2f37ce6 100644 --- a/components/drivers/misc/rt_drv_pwm.c +++ b/components/drivers/misc/rt_drv_pwm.c @@ -88,21 +88,36 @@ static rt_size_t _pwm_write(rt_device_t dev, rt_off_t pos, const void *buffer, r return size; } +#ifdef RT_USING_DEVICE_OPS +static const struct rt_device_ops pwm_device_ops = +{ + RT_NULL, + RT_NULL, + RT_NULL, + _pwm_read, + _pwm_write, + _pwm_control +}; +#endif /* RT_USING_DEVICE_OPS */ + rt_err_t rt_device_pwm_register(struct rt_device_pwm *device, const char *name, const struct rt_pwm_ops *ops, const void *user_data) { rt_err_t result = RT_EOK; memset(device, 0, sizeof(struct rt_device_pwm)); - device->parent.type = RT_Device_Class_Miscellaneous; - - device->parent.init = RT_NULL; - device->parent.open = RT_NULL; - device->parent.close = RT_NULL; - device->parent.read = _pwm_read; - device->parent.write = _pwm_write; - device->parent.control = _pwm_control; +#ifdef RT_USING_DEVICE_OPS + device->parent.ops = &pwm_device_ops; +#else + device->parent.init = RT_NULL; + device->parent.open = RT_NULL; + device->parent.close = RT_NULL; + device->parent.read = _pwm_read; + device->parent.write = _pwm_write; + device->parent.control = _pwm_control; +#endif /* RT_USING_DEVICE_OPS */ + device->parent.type = RT_Device_Class_Miscellaneous; device->ops = ops; device->parent.user_data = (void *)user_data; diff --git a/components/drivers/pm/pm.c b/components/drivers/pm/pm.c index 655c4b4c02e180e7141729685142a436012c46f9..c300414444e651024f284fefcd6035d8f02274f1 100644 --- a/components/drivers/pm/pm.c +++ b/components/drivers/pm/pm.c @@ -151,11 +151,10 @@ void rt_pm_enter(void) /* enter sleep and wait to be waken up */ pm->ops->enter(pm); - rt_hw_interrupt_enable(level); - /* exit from low power mode */ rt_pm_exit(); + rt_hw_interrupt_enable(level); return ; } } diff --git a/components/drivers/serial/serial.c b/components/drivers/serial/serial.c index 959d8444c10b7c3a53edb1724be21d502608a0e7..c5932df7d9db6eeb914db216b189b97e164f1e5a 100644 --- a/components/drivers/serial/serial.c +++ b/components/drivers/serial/serial.c @@ -21,6 +21,7 @@ * 2017-11-07 JasonJia fix data bits error issue when using tcsetattr. * 2017-11-15 JasonJia fix poll rx issue when data is full. * add TCFLSH and FIONREAD support. + * 2018-12-08 Ernest Chen add DMA choice */ #include @@ -328,6 +329,7 @@ rt_inline int _serial_int_tx(struct rt_serial_device *serial, const rt_uint8_t * return size - length; } +#if defined(RT_USING_POSIX) || defined(RT_SERIAL_USING_DMA) static rt_size_t _serial_fifo_calc_recved_len(struct rt_serial_device *serial) { struct rt_serial_rx_fifo *rx_fifo = (struct rt_serial_rx_fifo *) serial->serial_rx; @@ -350,7 +352,9 @@ static rt_size_t _serial_fifo_calc_recved_len(struct rt_serial_device *serial) } } } +#endif /* RT_USING_POSIX || RT_SERIAL_USING_DMA */ +#ifdef RT_SERIAL_USING_DMA /** * Calculate DMA received data length. * @@ -527,6 +531,7 @@ rt_inline int _serial_dma_tx(struct rt_serial_device *serial, const rt_uint8_t * return 0; } } +#endif /* RT_SERIAL_USING_DMA */ /* RT-Thread Device Interface */ /* @@ -561,11 +566,13 @@ static rt_err_t rt_serial_open(struct rt_device *dev, rt_uint16_t oflag) LOG_D("open serial device: 0x%08x with open flag: 0x%04x", dev, oflag); +#ifdef RT_SERIAL_USING_DMA /* check device flag with the open flag */ if ((oflag & RT_DEVICE_FLAG_DMA_RX) && !(dev->flag & RT_DEVICE_FLAG_DMA_RX)) return -RT_EIO; if ((oflag & RT_DEVICE_FLAG_DMA_TX) && !(dev->flag & RT_DEVICE_FLAG_DMA_TX)) return -RT_EIO; +#endif /* RT_SERIAL_USING_DMA */ if ((oflag & RT_DEVICE_FLAG_INT_RX) && !(dev->flag & RT_DEVICE_FLAG_INT_RX)) return -RT_EIO; if ((oflag & RT_DEVICE_FLAG_INT_TX) && !(dev->flag & RT_DEVICE_FLAG_INT_TX)) @@ -580,8 +587,27 @@ static rt_err_t rt_serial_open(struct rt_device *dev, rt_uint16_t oflag) /* initialize the Rx/Tx structure according to open flag */ if (serial->serial_rx == RT_NULL) - { - if (oflag & RT_DEVICE_FLAG_DMA_RX) + { + if (oflag & RT_DEVICE_FLAG_INT_RX) + { + struct rt_serial_rx_fifo* rx_fifo; + + rx_fifo = (struct rt_serial_rx_fifo*) rt_malloc (sizeof(struct rt_serial_rx_fifo) + + serial->config.bufsz); + RT_ASSERT(rx_fifo != RT_NULL); + rx_fifo->buffer = (rt_uint8_t*) (rx_fifo + 1); + rt_memset(rx_fifo->buffer, 0, serial->config.bufsz); + rx_fifo->put_index = 0; + rx_fifo->get_index = 0; + rx_fifo->is_full = RT_FALSE; + + serial->serial_rx = rx_fifo; + dev->open_flag |= RT_DEVICE_FLAG_INT_RX; + /* configure low level device */ + serial->ops->control(serial, RT_DEVICE_CTRL_SET_INT, (void *)RT_DEVICE_FLAG_INT_RX); + } +#ifdef RT_SERIAL_USING_DMA + else if (oflag & RT_DEVICE_FLAG_DMA_RX) { if (serial->config.bufsz == 0) { struct rt_serial_rx_dma* rx_dma; @@ -608,24 +634,7 @@ static rt_err_t rt_serial_open(struct rt_device *dev, rt_uint16_t oflag) } dev->open_flag |= RT_DEVICE_FLAG_DMA_RX; } - else if (oflag & RT_DEVICE_FLAG_INT_RX) - { - struct rt_serial_rx_fifo* rx_fifo; - - rx_fifo = (struct rt_serial_rx_fifo*) rt_malloc (sizeof(struct rt_serial_rx_fifo) + - serial->config.bufsz); - RT_ASSERT(rx_fifo != RT_NULL); - rx_fifo->buffer = (rt_uint8_t*) (rx_fifo + 1); - rt_memset(rx_fifo->buffer, 0, serial->config.bufsz); - rx_fifo->put_index = 0; - rx_fifo->get_index = 0; - rx_fifo->is_full = RT_FALSE; - - serial->serial_rx = rx_fifo; - dev->open_flag |= RT_DEVICE_FLAG_INT_RX; - /* configure low level device */ - serial->ops->control(serial, RT_DEVICE_CTRL_SET_INT, (void *)RT_DEVICE_FLAG_INT_RX); - } +#endif /* RT_SERIAL_USING_DMA */ else { serial->serial_rx = RT_NULL; @@ -633,28 +642,17 @@ static rt_err_t rt_serial_open(struct rt_device *dev, rt_uint16_t oflag) } else { - if (oflag & RT_DEVICE_FLAG_DMA_RX) - dev->open_flag |= RT_DEVICE_FLAG_DMA_RX; - else if (oflag & RT_DEVICE_FLAG_INT_RX) + if (oflag & RT_DEVICE_FLAG_INT_RX) dev->open_flag |= RT_DEVICE_FLAG_INT_RX; +#ifdef RT_SERIAL_USING_DMA + else if (oflag & RT_DEVICE_FLAG_DMA_RX) + dev->open_flag |= RT_DEVICE_FLAG_DMA_RX; +#endif /* RT_SERIAL_USING_DMA */ } if (serial->serial_tx == RT_NULL) { - if (oflag & RT_DEVICE_FLAG_DMA_TX) - { - struct rt_serial_tx_dma* tx_dma; - - tx_dma = (struct rt_serial_tx_dma*) rt_malloc (sizeof(struct rt_serial_tx_dma)); - RT_ASSERT(tx_dma != RT_NULL); - tx_dma->activated = RT_FALSE; - - rt_data_queue_init(&(tx_dma->data_queue), 8, 4, RT_NULL); - serial->serial_tx = tx_dma; - - dev->open_flag |= RT_DEVICE_FLAG_DMA_TX; - } - else if (oflag & RT_DEVICE_FLAG_INT_TX) + if (oflag & RT_DEVICE_FLAG_INT_TX) { struct rt_serial_tx_fifo *tx_fifo; @@ -668,6 +666,21 @@ static rt_err_t rt_serial_open(struct rt_device *dev, rt_uint16_t oflag) /* configure low level device */ serial->ops->control(serial, RT_DEVICE_CTRL_SET_INT, (void *)RT_DEVICE_FLAG_INT_TX); } +#ifdef RT_SERIAL_USING_DMA + else if (oflag & RT_DEVICE_FLAG_DMA_TX) + { + struct rt_serial_tx_dma* tx_dma; + + tx_dma = (struct rt_serial_tx_dma*) rt_malloc (sizeof(struct rt_serial_tx_dma)); + RT_ASSERT(tx_dma != RT_NULL); + tx_dma->activated = RT_FALSE; + + rt_data_queue_init(&(tx_dma->data_queue), 8, 4, RT_NULL); + serial->serial_tx = tx_dma; + + dev->open_flag |= RT_DEVICE_FLAG_DMA_TX; + } +#endif /* RT_SERIAL_USING_DMA */ else { serial->serial_tx = RT_NULL; @@ -675,10 +688,12 @@ static rt_err_t rt_serial_open(struct rt_device *dev, rt_uint16_t oflag) } else { - if (oflag & RT_DEVICE_FLAG_DMA_TX) - dev->open_flag |= RT_DEVICE_FLAG_DMA_TX; - else if (oflag & RT_DEVICE_FLAG_INT_TX) + if (oflag & RT_DEVICE_FLAG_INT_TX) dev->open_flag |= RT_DEVICE_FLAG_INT_TX; +#ifdef RT_SERIAL_USING_DMA + else if (oflag & RT_DEVICE_FLAG_DMA_TX) + dev->open_flag |= RT_DEVICE_FLAG_DMA_TX; +#endif /* RT_SERIAL_USING_DMA */ } /* set stream flag */ @@ -710,6 +725,7 @@ static rt_err_t rt_serial_close(struct rt_device *dev) /* configure low level device */ serial->ops->control(serial, RT_DEVICE_CTRL_CLR_INT, (void*)RT_DEVICE_FLAG_INT_RX); } +#ifdef RT_SERIAL_USING_DMA else if (dev->open_flag & RT_DEVICE_FLAG_DMA_RX) { if (serial->config.bufsz == 0) { @@ -732,7 +748,8 @@ static rt_err_t rt_serial_close(struct rt_device *dev) serial->serial_rx = RT_NULL; dev->open_flag &= ~RT_DEVICE_FLAG_DMA_RX; } - +#endif /* RT_SERIAL_USING_DMA */ + if (dev->open_flag & RT_DEVICE_FLAG_INT_TX) { struct rt_serial_tx_fifo* tx_fifo; @@ -746,6 +763,7 @@ static rt_err_t rt_serial_close(struct rt_device *dev) /* configure low level device */ serial->ops->control(serial, RT_DEVICE_CTRL_CLR_INT, (void*)RT_DEVICE_FLAG_INT_TX); } +#ifdef RT_SERIAL_USING_DMA else if (dev->open_flag & RT_DEVICE_FLAG_DMA_TX) { struct rt_serial_tx_dma* tx_dma; @@ -757,7 +775,7 @@ static rt_err_t rt_serial_close(struct rt_device *dev) serial->serial_tx = RT_NULL; dev->open_flag &= ~RT_DEVICE_FLAG_DMA_TX; } - +#endif /* RT_SERIAL_USING_DMA */ return RT_EOK; } @@ -777,10 +795,12 @@ static rt_size_t rt_serial_read(struct rt_device *dev, { return _serial_int_rx(serial, buffer, size); } +#ifdef RT_SERIAL_USING_DMA else if (dev->open_flag & RT_DEVICE_FLAG_DMA_RX) { return _serial_dma_rx(serial, buffer, size); } +#endif /* RT_SERIAL_USING_DMA */ return _serial_poll_rx(serial, buffer, size); } @@ -801,10 +821,12 @@ static rt_size_t rt_serial_write(struct rt_device *dev, { return _serial_int_tx(serial, buffer, size); } +#ifdef RT_SERIAL_USING_DMA else if (dev->open_flag & RT_DEVICE_FLAG_DMA_TX) { return _serial_dma_tx(serial, buffer, size); } +#endif /* RT_SERIAL_USING_DMA */ else { return _serial_poll_tx(serial, buffer, size); @@ -1181,12 +1203,13 @@ void rt_hw_serial_isr(struct rt_serial_device *serial, int event) rt_completion_done(&(tx_fifo->completion)); break; } +#ifdef RT_SERIAL_USING_DMA case RT_SERIAL_EVENT_TX_DMADONE: { const void *data_ptr; rt_size_t data_size; const void *last_data_ptr; - struct rt_serial_tx_dma* tx_dma; + struct rt_serial_tx_dma *tx_dma; tx_dma = (struct rt_serial_tx_dma*) serial->serial_tx; @@ -1246,6 +1269,7 @@ void rt_hw_serial_isr(struct rt_serial_device *serial, int event) } break; } +#endif /* RT_SERIAL_USING_DMA */ } } diff --git a/components/drivers/spi/SConscript b/components/drivers/spi/SConscript index ee423c33db428305c8dae0cd1684e9f330630115..b88671ebc93e8a554bf262efbf495663f98dbb1a 100644 --- a/components/drivers/spi/SConscript +++ b/components/drivers/spi/SConscript @@ -6,6 +6,9 @@ src = ['spi_core.c', 'spi_dev.c'] CPPPATH = [cwd, cwd + '/../include'] LOCAL_CCFLAGS = '' +if GetDepend('RT_USING_QSPI'): + src += ['qspi_core.c'] + src_device = [] if GetDepend('RT_USING_SPI_WIFI'): diff --git a/components/drivers/spi/qspi_core.c b/components/drivers/spi/qspi_core.c new file mode 100644 index 0000000000000000000000000000000000000000..c9ff6a963799a9b179d907236fb044029f20b843 --- /dev/null +++ b/components/drivers/spi/qspi_core.c @@ -0,0 +1,265 @@ +/* + * Copyright (c) 2006-2018, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2018-11-16 zylx first version. + */ + +#include + +rt_err_t rt_qspi_configure(struct rt_qspi_device *device, struct rt_qspi_configuration *cfg) +{ + RT_ASSERT(device != RT_NULL); + RT_ASSERT(cfg != RT_NULL); + + struct rt_qspi_device *qspi_device = (struct rt_qspi_device *)device; + rt_err_t result = RT_EOK; + + /* copy configuration items */ + qspi_device->config.parent.mode = cfg->parent.mode; + qspi_device->config.parent.max_hz = cfg->parent.max_hz; + qspi_device->config.parent.data_width = cfg->parent.data_width; + qspi_device->config.parent.reserved = cfg->parent.reserved; + qspi_device->config.medium_size = cfg->medium_size; + qspi_device->config.ddr_mode = cfg->ddr_mode; + qspi_device->config.qspi_dl_width = cfg->qspi_dl_width; + + result = rt_spi_configure(&device->parent, &cfg->parent); + + return result; +} + +rt_err_t rt_qspi_bus_register(struct rt_spi_bus *bus, const char *name, const struct rt_spi_ops *ops) +{ + rt_err_t result = RT_EOK; + + result = rt_spi_bus_register(bus, name, ops); + if(result == RT_EOK) + { + /* set SPI bus to qspi modes */ + bus->mode = RT_SPI_BUS_MODE_QSPI; + } + + return result; +} + +rt_size_t rt_qspi_transfer_message(struct rt_qspi_device *device, struct rt_qspi_message *message) +{ + rt_err_t result; + + RT_ASSERT(device != RT_NULL); + RT_ASSERT(message != RT_NULL); + + result = rt_mutex_take(&(device->parent.bus->lock), RT_WAITING_FOREVER); + if (result != RT_EOK) + { + rt_set_errno(-RT_EBUSY); + + return 0; + } + + /* reset errno */ + rt_set_errno(RT_EOK); + + /* configure SPI bus */ + if (device->parent.bus->owner != &device->parent) + { + /* not the same owner as current, re-configure SPI bus */ + result = device->parent.bus->ops->configure(&device->parent, &device->parent.config); + if (result == RT_EOK) + { + /* set SPI bus owner */ + device->parent.bus->owner = &device->parent; + } + else + { + /* configure SPI bus failed */ + rt_set_errno(-RT_EIO); + goto __exit; + } + } + + /* transmit each SPI message */ + + result = device->parent.bus->ops->xfer(&device->parent, &message->parent); + if (result == 0) + { + rt_set_errno(-RT_EIO); + } + +__exit: + /* release bus lock */ + rt_mutex_release(&(device->parent.bus->lock)); + + return result; +} + +rt_err_t rt_qspi_send_then_recv(struct rt_qspi_device *device, const void *send_buf, rt_size_t send_length, void *recv_buf, rt_size_t recv_length) +{ + RT_ASSERT(send_buf); + RT_ASSERT(recv_buf); + RT_ASSERT(send_length != 0); + + struct rt_qspi_message message; + unsigned char *ptr = (unsigned char *)send_buf; + rt_size_t count = 0; + rt_err_t result = 0; + + message.instruction.content = ptr[0]; + message.instruction.qspi_lines = 1; + count++; + + /* get address */ + if (send_length > 1) + { + if (device->config.medium_size > 0x1000000 && send_length >= 5) + { + /* medium size greater than 16Mb, address size is 4 Byte */ + message.address.content = (ptr[1] << 24) | (ptr[2] << 16) | (ptr[3] << 8) | (ptr[4]); + message.address.size = 32; + count += 4; + } + else if (send_length >= 4) + { + /* address size is 3 Byte */ + message.address.content = (ptr[1] << 16) | (ptr[2] << 8) | (ptr[3]); + message.address.size = 24; + count += 3; + } + else + { + return -RT_ERROR; + } + message.address.qspi_lines = 1; + } + else + { + /* no address stage */ + message.address.content = 0 ; + message.address.qspi_lines = 0; + message.address.size = 0; + } + + message.alternate_bytes.content = 0; + message.alternate_bytes.size = 0; + message.alternate_bytes.qspi_lines = 0; + + /* set dummy cycles */ + if (count != send_length) + { + message.dummy_cycles = (send_length - count) * 8; + + } + else + { + message.dummy_cycles = 0; + } + + /* set recv buf and recv size */ + message.parent.recv_buf = recv_buf; + message.parent.send_buf = RT_NULL; + message.parent.length = recv_length; + message.parent.cs_take = 1; + message.parent.cs_release = 1; + + message.qspi_data_lines = 1; + + result = rt_qspi_transfer_message(device, &message); + if (result == 0) + { + result = -RT_EIO; + } + else + { + result = recv_length; + } + + return result; +} + +rt_err_t rt_qspi_send(struct rt_qspi_device *device, const void *send_buf, rt_size_t length) +{ + RT_ASSERT(send_buf); + RT_ASSERT(length != 0); + + struct rt_qspi_message message; + char *ptr = (char *)send_buf; + rt_size_t count = 0; + rt_err_t result = 0; + + message.instruction.content = ptr[0]; + message.instruction.qspi_lines = 1; + count++; + + /* get address */ + if (length > 1) + { + if (device->config.medium_size > 0x1000000 && length >= 5) + { + /* medium size greater than 16Mb, address size is 4 Byte */ + message.address.content = (ptr[1] << 24) | (ptr[2] << 16) | (ptr[3] << 8) | (ptr[4]); + message.address.size = 32; + message.address.qspi_lines = 1; + count += 4; + } + else if (length >= 4) + { + /* address size is 3 Byte */ + message.address.content = (ptr[1] << 16) | (ptr[2] << 8) | (ptr[3]); + message.address.size = 24; + message.address.qspi_lines = 1; + count += 3; + } + else + { + return -RT_ERROR; + } + + } + else + { + /* no address stage */ + message.address.content = 0 ; + message.address.qspi_lines = 0; + message.address.size = 0; + } + + message.alternate_bytes.content = 0; + message.alternate_bytes.size = 0; + message.alternate_bytes.qspi_lines = 0; + + message.dummy_cycles = 0; + + /* determine if there is data to send */ + if (length - count > 0) + { + message.qspi_data_lines = 1; + } + else + { + message.qspi_data_lines = 0; + + } + + /* set send buf and send size */ + message.parent.send_buf = ptr + count; + message.parent.recv_buf = RT_NULL; + message.parent.length = length - count; + message.parent.cs_take = 1; + message.parent.cs_release = 1; + + result = rt_qspi_transfer_message(device, &message); + if (result == 0) + { + result = -RT_EIO; + } + else + { + result = length; + } + + return result; +} diff --git a/components/drivers/spi/sfud/README.md b/components/drivers/spi/sfud/README.md index 7394321243522852bf7ad1274383701aaee2bb5b..c732d06dbe6773ebda1a00c4536240877ec06869 100644 --- a/components/drivers/spi/sfud/README.md +++ b/components/drivers/spi/sfud/README.md @@ -6,11 +6,13 @@ [SFUD](https://github.com/armink/SFUD) 是一款开源的串行 SPI Flash 通用驱动库。由于现有市面的串行 Flash 种类居多,各个 Flash 的规格及命令存在差异, SFUD 就是为了解决这些 Flash 的差异现状而设计,让我们的产品能够支持不同品牌及规格的 Flash,提高了涉及到 Flash 功能的软件的可重用性及可扩展性,同时也可以规避 Flash 缺货或停产给产品所带来的风险。 -- 主要特点:面向对象(同时支持多个 Flash 对象)、可灵活裁剪、扩展性强、支持 4 字节地址 +- 主要特点:支持 SPI/QSPI 接口、面向对象(同时支持多个 Flash 对象)、可灵活裁剪、扩展性强、支持 4 字节地址 - 资源占用 - 标准占用:RAM:0.2KB ROM:5.5KB - 最小占用:RAM:0.1KB ROM:3.6KB -- 设计思路:这里要首先跟大家介绍一个标准: **SFDP** ,它是 JEDEC (固态技术协会)制定的串行 Flash 功能的参数表标准,最新版 V1.6B ([点击这里查看](https://www.jedec.org/standards-documents/docs/jesd216b))。该标准规定了,每个 Flash 中会存在一个参数表,该表中会存放 Flash 容量、写粒度、擦除命令、地址模式等 Flash 规格参数。目前,除了部分厂家旧款 Flash 型号会不支持该标准,其他绝大多数新出厂的 Flash 均已支持 SFDP 标准。所以该库在初始化时会优先读取 SFDP 表参数,如果该 Flash 不支持 SFDP,则查询配置文件 ( [`/sfud/inc/sfud_flash_def.h`](https://github.com/armink/SFUD/blob/master/sfud/inc/sfud_flash_def.h#L110-L122) ) 中提供的 **Flash 参数信息表** 中是否支持该款 Flash。如果不支持,则可以在配置文件中添加该款 Flash 的参数信息(添加方法详细见 [2.5 添加库目前不支持的 Flash](#25-添加库目前不支持的-flash))。获取到了 Flash 的规格参数后,就可以实现对 Flash 的全部操作。 +- 设计思路: + - **什么是 SFDP** :它是 JEDEC (固态技术协会)制定的串行 Flash 功能的参数表标准,最新版 V1.6B ([点击这里查看](https://www.jedec.org/standards-documents/docs/jesd216b))。该标准规定了,每个 Flash 中会存在一个参数表,该表中会存放 Flash 容量、写粒度、擦除命令、地址模式等 Flash 规格参数。目前,除了部分厂家旧款 Flash 型号会不支持该标准,其他绝大多数新出厂的 Flash 均已支持 SFDP 标准。所以该库在初始化时会优先读取 SFDP 表参数。 + - **不支持 SFDP 怎么办** :如果该 Flash 不支持 SFDP 标准,SFUD 会查询配置文件 ( [`/sfud/inc/sfud_flash_def.h`](https://github.com/armink/SFUD/blob/4bee2d0417a7ce853cc7aa3639b03fe825611fd9/sfud/inc/sfud_flash_def.h#L116-L142) ) 中提供的 **Flash 参数信息表** 中是否支持该款 Flash。如果不支持,则可以在配置文件中添加该款 Flash 的参数信息(添加方法详细见 [2.5 添加库目前不支持的 Flash](#25-添加库目前不支持的-flash))。获取到了 Flash 的规格参数后,就可以实现对 Flash 的全部操作。 ## 1、为什么选择 SFUD @@ -23,37 +25,43 @@ ### 2.1 已支持 Flash -下表为所有在 Demo 平台上进行过真机测试的 Flash。目前 SFUD 提供的 **Flash 参数信息表** 只包括下表中 **不支持** SFDP 标准的 Flash,其他不支持 SFDP 标准的 Flash 需要大家以后 **共同来完善和维护** **([Github](https://github.com/armink/SFUD)|[OSChina](http://git.oschina.net/armink/SFUD)|[Coding](https://coding.net/u/armink/p/SFUD/git))** 。如果觉得这个开源项目很赞,可以点击 [项目主页](https://github.com/armink/SFUD) 右上角的 **Star** ,同时把它推荐给更多有需要的朋友。 - -|型号|制造商|容量|最高速度|SFDP 标准|备注| -|:--:|:----:|:--:|:--:|:--:|:--:| -|[W25Q40BV](http://microchip.ua/esp8266/W25Q40BV(EOL).pdf)|Winbond|4Mb|50Mhz|不支持|已停产| -|[W25Q80DV](http://www.winbond.com/resource-files/w25q80dv_revg_07212015.pdf)|Winbond|8Mb|104Mhz|支持|| -|[W25Q16BV](https://media.digikey.com/pdf/Data%20Sheets/Winbond%20PDFs/W25Q16BV.pdf)|Winbond|16Mb|104Mhz|不支持| by [slipperstree](https://github.com/slipperstree)| -|[W25Q16CV](http://www.winbond.com/resource-files/da00-w25q16cvf1.pdf)|Winbond|16Mb|104Mhz|支持|| -|[W25Q16DV](http://www.winbond.com/resource-files/w25q16dv%20revk%2005232016%20doc.pdf)|Winbond|16Mb|104Mhz|支持| by [slipperstree](https://github.com/slipperstree)| -|[W25Q32BV](http://www.winbond.com/resource-files/w25q32bv_revi_100413_wo_automotive.pdf)|Winbond|32Mb|104Mhz|支持|| -|[W25Q64CV](http://www.winbond.com/resource-files/w25q64cv_revh_052214[2].pdf)|Winbond|64Mb|80Mhz|支持|| -|[W25Q128BV](http://www.winbond.com/resource-files/w25q128bv_revh_100313_wo_automotive.pdf)|Winbond|128Mb|104Mhz|支持|| -|[W25Q256FV](http://www.winbond.com/resource-files/w25q256fv%20revi%2002262016%20kms.pdf)|Winbond|256Mb|104Mhz|支持|| -|[MX25L3206E](http://www.macronix.com/Lists/DataSheet/Attachments/3199/MX25L3206E,%203V,%2032Mb,%20v1.5.pdf)|Macronix|32Mb|86MHz|支持|| -|[KH25L4006E](http://www.macronix.com.hk/Lists/Datasheet/Attachments/117/KH25L4006E.pdf)|Macronix|4Mb|86Mhz|支持| by [JiapengLi](https://github.com/JiapengLi)| -|[KH25L3206E](http://www.macronix.com.hk/Lists/Datasheet/Attachments/131/KH25L3206E.pdf)|Macronix|32Mb|86Mhz|支持|| -|[SST25VF016B](http://ww1.microchip.com/downloads/en/DeviceDoc/20005044C.pdf)|Microchip|16Mb|50MHz|不支持| SST 已被 Microchip 收购| -|[M25P40](https://www.micron.com/~/media/documents/products/data-sheet/nor-flash/serial-nor/m25p/m25p40.pdf)|Micron|4Mb|75Mhz|不支持| by [redocCheng](https://github.com/redocCheng)| -|[M25P80](https://www.micron.com/~/media/documents/products/data-sheet/nor-flash/serial-nor/m25p/m25p80.pdf)|Micron|8Mb|75Mhz|不支持| by [redocCheng](https://github.com/redocCheng)| -|[M25P32](https://www.micron.com/~/media/documents/products/data-sheet/nor-flash/serial-nor/m25p/m25p32.pdf)|Micron|32Mb|75Mhz|不支持|| -|[EN25Q32B](http://www.kean.com.au/oshw/WR703N/teardown/EN25Q32B%2032Mbit%20SPI%20Flash.pdf)|EON|32Mb|104MHz|不支持|| -|[GD25Q16B](http://www.gigadevice.com/product/detail/5/410.html)|GigaDevice|16Mb|120Mhz|不支持| by [TanekLiang](https://github.com/TanekLiang) | -|[GD25Q64B](http://www.gigadevice.com/product/detail/5/364.html)|GigaDevice|64Mb|120Mhz|不支持|| -|[S25FL216K](http://www.cypress.com/file/197346/download)|Cypress|16Mb|65Mhz|不支持|| -|[S25FL032P](http://www.cypress.com/file/196861/download)|Cypress|32Mb|104Mhz|不支持| by [yc_911](https://gitee.com/yc_911) | -|[S25FL164K](http://www.cypress.com/file/196886/download)|Cypress|64Mb|108Mhz|支持|| -|[A25L080](http://www.amictechnology.com/datasheets/A25L080.pdf)|AMIC|8Mb|100Mhz|不支持|| -|[A25LQ64](http://www.amictechnology.com/datasheets/A25LQ64.pdf)|AMIC|64Mb|104Mhz|支持|| -|[F25L004](http://www.esmt.com.tw/db/manager/upload/f25l004.pdf)|ESMT|4Mb|100Mhz|不支持|| -|[PCT25VF016B](http://pctgroup.com.tw/attachments/files/files/248_25VF016B-P.pdf)|PCT|16Mb|80Mhz|不支持|SST 授权许可,会被识别为 SST25VF016B| -|[AT45DB161E](http://www.adestotech.com/wp-content/uploads/doc8782.pdf)|ADESTO|16Mb|85MHz|不支持|ADESTO 收购 Atmel 串行闪存产品线| +下表为所有已在 Demo 平台上进行过真机测试过的 Flash。显示为 **不支持** SFDP 标准的 Flash 已经在 Flash 参数信息表中定义,更多不支持 SFDP 标准的 Flash 需要大家以后 **共同来完善和维护** **([Github](https://github.com/armink/SFUD)|[OSChina](http://git.oschina.net/armink/SFUD)|[Coding](https://coding.net/u/armink/p/SFUD/git))** 。 + +如果觉得这个开源项目很赞,可以点击 [项目主页](https://github.com/armink/SFUD) 右上角的 **Star** ,同时把它推荐给更多有需要的朋友。 + +|型号|制造商|容量|最高速度|SFDP 标准|QSPI 模式|备注| +|:--:|:----:|:--:|:--:|:--:|:--:|----| +|[W25Q40BV](http://microchip.ua/esp8266/W25Q40BV(EOL).pdf)|Winbond|4Mb|50Mhz|不支持|双线|已停产| +|[W25Q80DV](http://www.winbond.com/resource-files/w25q80dv_revg_07212015.pdf)|Winbond|8Mb|104Mhz|支持|双线|| +|[W25Q16BV](https://media.digikey.com/pdf/Data%20Sheets/Winbond%20PDFs/W25Q16BV.pdf)|Winbond|16Mb|104Mhz|不支持|双线| by [slipperstree](https://github.com/slipperstree)| +|[W25Q16CV](http://www.winbond.com/resource-files/da00-w25q16cvf1.pdf)|Winbond|16Mb|104Mhz|支持|未测试|| +|[W25Q16DV](http://www.winbond.com/resource-files/w25q16dv%20revk%2005232016%20doc.pdf)|Winbond|16Mb|104Mhz|支持|未测试| by [slipperstree](https://github.com/slipperstree)| +|[W25Q32BV](http://www.winbond.com/resource-files/w25q32bv_revi_100413_wo_automotive.pdf)|Winbond|32Mb|104Mhz|支持|双线|| +|[W25Q64CV](http://www.winbond.com/resource-files/w25q64cv_revh_052214[2].pdf)|Winbond|64Mb|80Mhz|支持|四线|| +|[W25Q128BV](http://www.winbond.com/resource-files/w25q128bv_revh_100313_wo_automotive.pdf)|Winbond|128Mb|104Mhz|支持|四线|| +|[W25Q256FV](http://www.winbond.com/resource-files/w25q256fv%20revi%2002262016%20kms.pdf)|Winbond|256Mb|104Mhz|支持|四线|| +|[MX25L3206E](http://www.macronix.com/Lists/DataSheet/Attachments/3199/MX25L3206E,%203V,%2032Mb,%20v1.5.pdf)|Macronix|32Mb|86MHz|支持|双线|| +|[KH25L4006E](http://www.macronix.com.hk/Lists/Datasheet/Attachments/117/KH25L4006E.pdf)|Macronix|4Mb|86Mhz|支持|未测试| by [JiapengLi](https://github.com/JiapengLi)| +|[KH25L3206E](http://www.macronix.com.hk/Lists/Datasheet/Attachments/131/KH25L3206E.pdf)|Macronix|32Mb|86Mhz|支持|双线|| +|[SST25VF016B](http://ww1.microchip.com/downloads/en/DeviceDoc/20005044C.pdf)|Microchip|16Mb|50MHz|不支持|不支持| SST 已被 Microchip 收购| +|[M25P40](https://www.micron.com/~/media/documents/products/data-sheet/nor-flash/serial-nor/m25p/m25p40.pdf)|Micron|4Mb|75Mhz|不支持|未测试| by [redocCheng](https://github.com/redocCheng)| +|[M25P80](https://www.micron.com/~/media/documents/products/data-sheet/nor-flash/serial-nor/m25p/m25p80.pdf)|Micron|8Mb|75Mhz|不支持|未测试| by [redocCheng](https://github.com/redocCheng)| +|[M25P32](https://www.micron.com/~/media/documents/products/data-sheet/nor-flash/serial-nor/m25p/m25p32.pdf)|Micron|32Mb|75Mhz|不支持|不支持|| +|[EN25Q32B](http://www.kean.com.au/oshw/WR703N/teardown/EN25Q32B%2032Mbit%20SPI%20Flash.pdf)|EON|32Mb|104MHz|不支持|未测试|| +|[GD25Q16B](http://www.gigadevice.com/product/detail/5/410.html)|GigaDevice|16Mb|120Mhz|不支持|未测试| by [TanekLiang](https://github.com/TanekLiang) | +|[GD25Q64B](http://www.gigadevice.com/product/detail/5/364.html)|GigaDevice|64Mb|120Mhz|不支持|双线|| +|[S25FL216K](http://www.cypress.com/file/197346/download)|Cypress|16Mb|65Mhz|不支持|双线|| +|[S25FL032P](http://www.cypress.com/file/196861/download)|Cypress|32Mb|104Mhz|不支持|未测试| by [yc_911](https://gitee.com/yc_911) | +|[S25FL164K](http://www.cypress.com/file/196886/download)|Cypress|64Mb|108Mhz|支持|未测试|| +|[A25L080](http://www.amictechnology.com/datasheets/A25L080.pdf)|AMIC|8Mb|100Mhz|不支持|双线|| +|[A25LQ64](http://www.amictechnology.com/datasheets/A25LQ64.pdf)|AMIC|64Mb|104Mhz|支持|支持|| +|[F25L004](http://www.esmt.com.tw/db/manager/upload/f25l004.pdf)|ESMT|4Mb|100Mhz|不支持|不支持|| +|[PCT25VF016B](http://pctgroup.com.tw/attachments/files/files/248_25VF016B-P.pdf)|PCT|16Mb|80Mhz|不支持|不支持|SST 授权许可,会被识别为 SST25VF016B| +|[AT45DB161E](http://www.adestotech.com/wp-content/uploads/doc8782.pdf)|ADESTO|16Mb|85MHz|不支持|不支持|ADESTO 收购 Atmel 串行闪存产品线| + +> 注:QSPI 模式中,双线表示支持双线快读,四线表示支持四线快读。 +> +> 一般情况下,支持四线快读的 FLASH 也支持两线快读。 ### 2.2 API 说明 @@ -63,7 +71,7 @@ 将会调用 `sfud_device_init` ,初始化 Flash 设备表中的全部设备。如果只有一个 Flash 也可以只使用 `sfud_device_init` 进行单一初始化。 -> 注意:初始化完的 SPI Flash 默认都 **已取消写保护** 状态,如需开启写保护,请使用 sfud_write_status 函数修改 SPI Flash 状态。 +> **注意**:初始化完的 SPI Flash 默认都 **已取消写保护** 状态,如需开启写保护,请使用 sfud_write_status 函数修改 SPI Flash 状态。 ```C sfud_err sfud_init(void) @@ -79,7 +87,24 @@ sfud_err sfud_device_init(sfud_flash *flash) |:----- |:----| |flash |待初始化的 Flash 设备| -#### 2.2.3 获取 Flash 设备对象 +#### 2.2.3 使能快速读模式(仅当 SFUD 开启 QSPI 模式后可用) + +当 SFUD 开启 QSPI 模式后,SFUD 中的 Flash 驱动支持使用 QSPI 总线进行通信。相比传统的 SPI 模式,使用 QSPI 能够加速 Flash 数据的读取,但当数据需要写入时,由于 Flash 本身的数据写入速度慢于 SPI 传输速度,所以 QSPI 模式下的数据写入速度提升并不明显。 + +所以 SFUD 对于 QSPI 模式的支持仅限于快速读命令。通过该函数可以配置 Flash 所使用的 QSPI 总线的实际支持的数据线最大宽度,例如:1 线(默认值,即传统的 SPI 模式)、2 线、4 线。 + +设置后,SFUD 会去结合当前设定的 QSPI 总线数据线宽度,去 [QSPI Flash 扩展信息表](https://github.com/armink/SFUD/blob/069d2b409ec239f84d675b2c3d37894e908829e6/sfud/inc/sfud_flash_def.h#L149-L177) 中匹配最合适的、速度最快的快速读命令,之后用户在调用 sfud_read() 时,会使用 QSPI 模式的传输函数发送该命令。 + +```C +sfud_err sfud_qspi_fast_read_enable(sfud_flash *flash, uint8_t data_line_width) +``` + +| 参数 | 描述 | +| :-------------- | :------------------------------------------- | +| flash | Flash 设备 | +| data_line_width | QSPI 总线支持的数据线最大宽度,例如:1、2、4 | + +#### 2.2.4 获取 Flash 设备对象 在 SFUD 配置文件中会定义 Flash 设备表,负责存放所有将要使用的 Flash 设备对象,所以 SFUD 支持多个 Flash 设备同时驱动。设备表的配置在 `/sfud/inc/sfud_cfg.h` 中 `SFUD_FLASH_DEVICE_TABLE` 宏定义,详细配置方法参照 [2.3 配置方法 Flash](#23-配置方法))。本方法通过 Flash 设备位于设备表中索引值来返回 Flash 设备对象,超出设备表范围返回 `NULL` 。 @@ -91,7 +116,7 @@ sfud_flash *sfud_get_device(size_t index) |:----- |:----| |index |Flash 设备位于 FLash 设备表中的索引值| -#### 2.2.4 读取 Flash 数据 +#### 2.2.5 读取 Flash 数据 ```C sfud_err sfud_read(const sfud_flash *flash, uint32_t addr, size_t size, uint8_t *data) @@ -104,7 +129,7 @@ sfud_err sfud_read(const sfud_flash *flash, uint32_t addr, size_t size, uint8_t |size |从起始地址开始读取数据的总大小| |data |读取到的数据| -#### 2.2.5 擦除 Flash 数据 +#### 2.2.6 擦除 Flash 数据 > 注意:擦除操作将会按照 Flash 芯片的擦除粒度(详见 Flash 数据手册,一般为 block 大小。初始化完成后,可以通过 `sfud_flash->chip.erase_gran` 查看)对齐,请注意保证起始地址和擦除数据大小按照 Flash 芯片的擦除粒度对齐,否则执行擦除操作后,将会导致其他数据丢失。 @@ -118,7 +143,7 @@ sfud_err sfud_erase(const sfud_flash *flash, uint32_t addr, size_t size) |addr |起始地址| |size |从起始地址开始擦除数据的总大小| -#### 2.2.6 擦除 Flash 全部数据 +#### 2.2.7 擦除 Flash 全部数据 ```C sfud_err sfud_chip_erase(const sfud_flash *flash) @@ -128,7 +153,7 @@ sfud_err sfud_chip_erase(const sfud_flash *flash) |:----- |:----| |flash |Flash 设备对象| -#### 2.2.7 往 Flash 写数据 +#### 2.2.8 往 Flash 写数据 ```C sfud_err sfud_write(const sfud_flash *flash, uint32_t addr, size_t size, const uint8_t *data) @@ -141,7 +166,7 @@ sfud_err sfud_write(const sfud_flash *flash, uint32_t addr, size_t size, const u |size |从起始地址开始写入数据的总大小| |data |待写入的数据| -#### 2.2.8 先擦除再往 Flash 写数据 +#### 2.2.9 先擦除再往 Flash 写数据 > 注意:擦除操作将会按照 Flash 芯片的擦除粒度(详见 Flash 数据手册,一般为 block 大小。初始化完成后,可以通过 `sfud_flash->chip.erase_gran` 查看)对齐,请注意保证起始地址和擦除数据大小按照 Flash 芯片的擦除粒度对齐,否则执行擦除操作后,将会导致其他数据丢失。 @@ -156,7 +181,7 @@ sfud_err sfud_erase_write(const sfud_flash *flash, uint32_t addr, size_t size, c |size |从起始地址开始写入数据的总大小| |data |待写入的数据| -#### 2.2.9 读取 Flash 状态 +#### 2.2.10 读取 Flash 状态 ```C sfud_err sfud_read_status(const sfud_flash *flash, uint8_t *status) @@ -167,7 +192,7 @@ sfud_err sfud_read_status(const sfud_flash *flash, uint8_t *status) |flash |Flash 设备对象| |status |当前状态寄存器值| -#### 2.2.10 写(修改) Flash 状态 +#### 2.2.11 写(修改) Flash 状态 ```C sfud_err sfud_write_status(const sfud_flash *flash, bool is_volatile, uint8_t status) @@ -234,6 +259,12 @@ enum { 上面定义了两个 Flash 设备(大部分产品一个足以),两个设备的名称为 `"W25Q64CV"` 及 `"GD25Q64B"` ,分别对应 `"SPI1"` 及 `"SPI3"` 这两个 SPI 设备名称(在移植 SPI 接口时会用到,位于 `/sfud/port/sfud_port.c` ), `SFUD_W25Q16CV_DEVICE_INDEX` 与 `SFUD_GD25Q64B_DEVICE_INDEX` 这两个枚举定义了两个设备位于设备表中的索引,可以通过 `sfud_get_device_table()` 方法获取到设备表,再配合这个索引值来访问指定的设备。 +#### 2.3.6 QSPI 模式 + +打开/关闭 `SFUD_USING_QSPI` 宏定义 + +开启后,SFUD 也将支持使用 QSPI 总线连接的 Flash。 + ### 2.4 移植说明 移植文件位于 `/sfud/port/sfud_port.c` ,文件中的 `sfud_err sfud_spi_port_init(sfud_flash *flash)` 方法是库提供的移植方法,在里面完成各个设备 SPI 读写驱动(必选)、重试次数(必选)、重试接口(可选)及 SPI 锁(可选)的配置。更加详细的移植内容,可以参考 demo 中的各个平台的移植文件。 @@ -258,6 +289,7 @@ enum { |:----- |:----| |[/demo/stm32f10x_non_os](https://github.com/armink/SFUD/tree/master/demo/stm32f10x_non_os) |STM32F10X 裸机平台| |[/demo/stm32f2xx_rtt](https://github.com/armink/SFUD/tree/master/demo/stm32f2xx_rtt) |STM32F2XX + [RT-Thread](http://www.rt-thread.org/) 操作系统平台| +|[/demo/stm32l475_non_os_qspi](https://github.com/armink/SFUD/tree/master/demo/stm32l475_non_os_qspi) |STM32L475 + QSPI 模式 裸机平台| ### 2.7 许可 diff --git a/components/drivers/spi/sfud/inc/sfud.h b/components/drivers/spi/sfud/inc/sfud.h index be1ccb208eb63a0ff1a62f786458e0e61c86b586..2b68c38216f707f8d20ae007529ec74c4e769ef4 100644 --- a/components/drivers/spi/sfud/inc/sfud.h +++ b/components/drivers/spi/sfud/inc/sfud.h @@ -1,7 +1,7 @@ /* * This file is part of the Serial Flash Universal Driver Library. * - * Copyright (c) 2016, Armink, + * Copyright (c) 2016-2018, Armink, * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -75,6 +75,23 @@ size_t sfud_get_device_num(void); */ const sfud_flash *sfud_get_device_table(void); +#ifdef SFUD_USING_QSPI +/** + * Enbale the fast read mode in QSPI flash mode. Default read mode is normal SPI mode. + * + * it will find the appropriate fast-read instruction to replace the read instruction(0x03) + * fast-read instruction @see SFUD_FLASH_EXT_INFO_TABLE + * + * @note When Flash is in QSPI mode, the method must be called after sfud_device_init(). + * + * @param flash flash device + * @param data_line_width the data lines max width which QSPI bus supported, such as 1, 2, 4 + * + * @return result + */ +sfud_err sfud_qspi_fast_read_enable(sfud_flash *flash, uint8_t data_line_width); +#endif /* SFUD_USING_QSPI */ + /** * read flash data * diff --git a/components/drivers/spi/sfud/inc/sfud_cfg.h b/components/drivers/spi/sfud/inc/sfud_cfg.h index 59189a9693da402949a0ce0e356f2cf03b7aac23..051de6d577fa943a55e75262b6fce4127b81add4 100644 --- a/components/drivers/spi/sfud/inc/sfud_cfg.h +++ b/components/drivers/spi/sfud/inc/sfud_cfg.h @@ -45,6 +45,13 @@ #define SFUD_USING_SFDP #endif +/** + * SFUD will support QSPI mode. + */ +#ifdef RT_SFUD_USING_QSPI +#define SFUD_USING_QSPI +#endif + /** * Using probe flash JEDEC ID then query defined supported flash chip information table. @see SFUD_FLASH_CHIP_TABLE */ diff --git a/components/drivers/spi/sfud/inc/sfud_def.h b/components/drivers/spi/sfud/inc/sfud_def.h index 1b0e8a3986331f3d6cd2e533fecf51f348df0859..fe7876618ba6b55362fe735b5c7a5d3f765ab07a 100644 --- a/components/drivers/spi/sfud/inc/sfud_def.h +++ b/components/drivers/spi/sfud/inc/sfud_def.h @@ -1,7 +1,7 @@ /* * This file is part of the Serial Flash Universal Driver Library. * - * Copyright (c) 2016, Armink, + * Copyright (c) 2016-2018, Armink, * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -78,7 +78,7 @@ if (!(EXPR)) \ else {if (__delay_temp) {__delay_temp();} retry --;} /* software version number */ -#define SFUD_SW_VERSION "1.0.6" +#define SFUD_SW_VERSION "1.1.0" /* * all defined supported command */ @@ -118,6 +118,22 @@ if (!(EXPR)) \ #define SFUD_CMD_READ_DATA 0x03 #endif +#ifndef SFUD_CMD_DUAL_OUTPUT_READ_DATA +#define SFUD_CMD_DUAL_OUTPUT_READ_DATA 0x3B +#endif + +#ifndef SFUD_CMD_DUAL_IO_READ_DATA +#define SFUD_CMD_DUAL_IO_READ_DATA 0xBB +#endif + +#ifndef SFUD_CMD_QUAD_IO_READ_DATA +#define SFUD_CMD_QUAD_IO_READ_DATA 0xEB +#endif + +#ifndef SFUD_CMD_QUAD_OUTPUT_READ_DATA +#define SFUD_CMD_QUAD_OUTPUT_READ_DATA 0x6B +#endif + #ifndef SFUD_CMD_MANUFACTURER_DEVICE_ID #define SFUD_CMD_MANUFACTURER_DEVICE_ID 0x90 #endif @@ -183,6 +199,21 @@ typedef enum { SFUD_ERR_ADDR_OUT_OF_BOUND = 5, /**< address is out of flash bound */ } sfud_err; +#ifdef SFUD_USING_QSPI +/** + * QSPI flash read cmd format + */ +typedef struct { + uint8_t instruction; + uint8_t instruction_lines; + uint8_t address_size; + uint8_t address_lines; + uint8_t alternate_bytes_lines; + uint8_t dummy_cycles; + uint8_t data_lines; +} sfud_qspi_read_cmd_format; +#endif /* SFUD_USING_QSPI */ + /* SPI bus write read data function type */ typedef sfud_err (*spi_write_read_func)(const uint8_t *write_buf, size_t write_size, uint8_t *read_buf, size_t read_size); @@ -218,7 +249,12 @@ typedef struct __sfud_spi { char *name; /* SPI bus write read data function */ sfud_err (*wr)(const struct __sfud_spi *spi, const uint8_t *write_buf, size_t write_size, uint8_t *read_buf, - size_t read_size); + size_t read_size); +#ifdef SFUD_USING_QSPI + /* QSPI fast read function */ + sfud_err (*qspi_read)(const struct __sfud_spi *spi, uint32_t addr, sfud_qspi_read_cmd_format *qspi_read_cmd_format, + uint8_t *read_buf, size_t read_size); +#endif /* lock SPI bus */ void (*lock)(const struct __sfud_spi *spi); /* unlock SPI bus */ @@ -243,6 +279,10 @@ typedef struct { } retry; void *user_data; /**< some user data */ +#ifdef SFUD_USING_QSPI + sfud_qspi_read_cmd_format read_cmd_format; /**< fast read cmd format */ +#endif + #ifdef SFUD_USING_SFDP sfud_sfdp sfdp; /**< serial flash discoverable parameters by JEDEC standard */ #endif diff --git a/components/drivers/spi/sfud/inc/sfud_flash_def.h b/components/drivers/spi/sfud/inc/sfud_flash_def.h index 2022a043b2fe7f70c287d10995e9b4d3390a70de..89223755573b87a422d633f2bef934e5d35f2a12 100644 --- a/components/drivers/spi/sfud/inc/sfud_flash_def.h +++ b/components/drivers/spi/sfud/inc/sfud_flash_def.h @@ -1,7 +1,7 @@ /* * This file is part of the Serial Flash Universal Driver Library. * - * Copyright (c) 2016-2017, Armink, + * Copyright (c) 2016-2018, Armink, * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -59,11 +59,21 @@ typedef struct { uint8_t type_id; /**< memory type ID */ uint8_t capacity_id; /**< capacity ID */ uint32_t capacity; /**< flash capacity (bytes) */ - uint16_t write_mode; /**< write mode @see sfud_write_mode */ + uint16_t write_mode; /**< write mode @see sfud_write_mode */ uint32_t erase_gran; /**< erase granularity (bytes) */ uint8_t erase_gran_cmd; /**< erase granularity size block command */ } sfud_flash_chip; +#ifdef SFUD_USING_QSPI +/* QSPI flash chip's extended information compared with SPI flash */ +typedef struct { + uint8_t mf_id; /**< manufacturer ID */ + uint8_t type_id; /**< memory type ID */ + uint8_t capacity_id; /**< capacity ID */ + uint8_t read_mode; /**< supported read mode on this qspi flash chip */ +} sfud_qspi_flash_ext_info; +#endif + /* SFUD support manufacturer JEDEC ID */ #define SFUD_MF_ID_CYPRESS 0x01 #define SFUD_MF_ID_FUJITSU 0x04 @@ -131,6 +141,42 @@ typedef struct { } #endif /* SFUD_USING_FLASH_INFO_TABLE */ +#ifdef SFUD_USING_QSPI +/* This table saves flash read-fast instructions in QSPI mode, + * SFUD can use this table to select the most appropriate read instruction for flash. + * | mf_id | type_id | capacity_id | qspi_read_mode | + */ +#define SFUD_FLASH_EXT_INFO_TABLE \ +{ \ + /* W25Q40BV */ \ + {SFUD_MF_ID_WINBOND, 0x40, 0x13, NORMAL_SPI_READ|DUAL_OUTPUT}, \ + /* W25Q80JV */ \ + {SFUD_MF_ID_WINBOND, 0x40, 0x14, NORMAL_SPI_READ|DUAL_OUTPUT}, \ + /* W25Q16BV */ \ + {SFUD_MF_ID_WINBOND, 0x40, 0x15, NORMAL_SPI_READ|DUAL_OUTPUT}, \ + /* W25Q32BV */ \ + {SFUD_MF_ID_WINBOND, 0x40, 0x16, NORMAL_SPI_READ|DUAL_OUTPUT}, \ + /* W25Q64JV */ \ + {SFUD_MF_ID_WINBOND, 0x40, 0x17, NORMAL_SPI_READ|DUAL_OUTPUT|DUAL_IO|QUAD_OUTPUT|QUAD_IO}, \ + /* W25Q128JV */ \ + {SFUD_MF_ID_WINBOND, 0x40, 0x18, NORMAL_SPI_READ|DUAL_OUTPUT|DUAL_IO|QUAD_OUTPUT|QUAD_IO}, \ + /* W25Q256FV */ \ + {SFUD_MF_ID_WINBOND, 0x40, 0x19, NORMAL_SPI_READ|DUAL_OUTPUT|DUAL_IO|QUAD_OUTPUT|QUAD_IO}, \ + /* EN25Q32B */ \ + {SFUD_MF_ID_EON, 0x30, 0x16, NORMAL_SPI_READ|DUAL_OUTPUT|QUAD_IO}, \ + /* S25FL216K */ \ + {SFUD_MF_ID_CYPRESS, 0x40, 0x15, NORMAL_SPI_READ|DUAL_OUTPUT}, \ + /* A25L080 */ \ + {SFUD_MF_ID_AMIC, 0x30, 0x14, NORMAL_SPI_READ|DUAL_OUTPUT|DUAL_IO}, \ + /* A25LQ64 */ \ + {SFUD_MF_ID_AMIC, 0x40, 0x17, NORMAL_SPI_READ|DUAL_OUTPUT|DUAL_IO|QUAD_IO}, \ + /* MX25L3206E and KH25L3206E */ \ + {SFUD_MF_ID_MICRONIX, 0x20, 0x16, NORMAL_SPI_READ|DUAL_OUTPUT}, \ + /* GD25Q64B */ \ + {SFUD_MF_ID_GIGADEVICE, 0x40, 0x17, NORMAL_SPI_READ|DUAL_OUTPUT}, \ +} +#endif /* SFUD_USING_QSPI */ + #ifdef __cplusplus } #endif diff --git a/components/drivers/spi/sfud/src/sfud.c b/components/drivers/spi/sfud/src/sfud.c index e3376555ca909f192a5180b5bfa720847c9845f4..30e0d949f1e7ddcc2d56786c80edd96fa679b206 100644 --- a/components/drivers/spi/sfud/src/sfud.c +++ b/components/drivers/spi/sfud/src/sfud.c @@ -1,7 +1,7 @@ /* * This file is part of the Serial Flash Universal Driver Library. * - * Copyright (c) 2016, Armink, + * Copyright (c) 2016-2018, Armink, * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -46,6 +46,22 @@ static const sfud_mf mf_table[] = SFUD_MF_TABLE; static const sfud_flash_chip flash_chip_table[] = SFUD_FLASH_CHIP_TABLE; #endif +#ifdef SFUD_USING_QSPI +/** + * flash read data mode + */ +enum sfud_qspi_read_mode { + NORMAL_SPI_READ = 1 << 0, /**< mormal spi read mode */ + DUAL_OUTPUT = 1 << 1, /**< qspi fast read dual output */ + DUAL_IO = 1 << 2, /**< qspi fast read dual input/output */ + QUAD_OUTPUT = 1 << 3, /**< qspi fast read quad output */ + QUAD_IO = 1 << 4, /**< qspi fast read quad input/output */ +}; + +/* QSPI flash chip's extended information table */ +static const sfud_qspi_flash_ext_info qspi_flash_ext_info_table[] = SFUD_FLASH_EXT_INFO_TABLE; +#endif /* SFUD_USING_QSPI */ + static sfud_err software_init(const sfud_flash *flash); static sfud_err hardware_init(sfud_flash *flash); static sfud_err page256_or_1_byte_write(const sfud_flash *flash, uint32_t addr, size_t size, uint16_t write_gran, @@ -146,11 +162,89 @@ const sfud_flash *sfud_get_device_table(void) { return flash_table; } +#ifdef SFUD_USING_QSPI +static void qspi_set_read_cmd_format(sfud_flash *flash, uint8_t ins, uint8_t ins_lines, uint8_t addr_lines, + uint8_t dummy_cycles, uint8_t data_lines) { + /* if medium size greater than 16Mb, use 4-Byte address, instruction should be added one */ + if (flash->chip.capacity <= 0x1000000) { + flash->read_cmd_format.instruction = ins; + flash->read_cmd_format.address_size = 24; + } else { + flash->read_cmd_format.instruction = ins + 1; + flash->read_cmd_format.address_size = 32; + } + + flash->read_cmd_format.instruction_lines = ins_lines; + flash->read_cmd_format.address_lines = addr_lines; + flash->read_cmd_format.alternate_bytes_lines = 0; + flash->read_cmd_format.dummy_cycles = dummy_cycles; + flash->read_cmd_format.data_lines = data_lines; +} + +/** + * Enbale the fast read mode in QSPI flash mode. Default read mode is normal SPI mode. + * + * it will find the appropriate fast-read instruction to replace the read instruction(0x03) + * fast-read instruction @see SFUD_FLASH_EXT_INFO_TABLE + * + * @note When Flash is in QSPI mode, the method must be called after sfud_device_init(). + * + * @param flash flash device + * @param data_line_width the data lines max width which QSPI bus supported, such as 1, 2, 4 + * + * @return result + */ +sfud_err sfud_qspi_fast_read_enable(sfud_flash *flash, uint8_t data_line_width) { + size_t i = 0; + uint8_t read_mode = NORMAL_SPI_READ; + sfud_err result = SFUD_SUCCESS; + + SFUD_ASSERT(flash); + SFUD_ASSERT(data_line_width == 1 || data_line_width == 2 || data_line_width == 4); + + /* get read_mode, If don't found, the default is SFUD_QSPI_NORMAL_SPI_READ */ + for (i = 0; i < sizeof(qspi_flash_ext_info_table) / sizeof(sfud_qspi_flash_ext_info); i++) { + if ((qspi_flash_ext_info_table[i].mf_id == flash->chip.mf_id) + && (qspi_flash_ext_info_table[i].type_id == flash->chip.type_id) + && (qspi_flash_ext_info_table[i].capacity_id == flash->chip.capacity_id)) { + read_mode = qspi_flash_ext_info_table[i].read_mode; + } + } + + /* determine qspi supports which read mode and set read_cmd_format struct */ + switch (data_line_width) { + case 1: + qspi_set_read_cmd_format(flash, SFUD_CMD_READ_DATA, 1, 1, 0, 1); + break; + case 2: + if (read_mode & DUAL_IO) { + qspi_set_read_cmd_format(flash, SFUD_CMD_DUAL_IO_READ_DATA, 1, 2, 8, 2); + } else if (read_mode & DUAL_OUTPUT) { + qspi_set_read_cmd_format(flash, SFUD_CMD_DUAL_OUTPUT_READ_DATA, 1, 1, 8, 2); + } else { + qspi_set_read_cmd_format(flash, SFUD_CMD_READ_DATA, 1, 1, 0, 1); + } + break; + case 4: + if (read_mode & QUAD_IO) { + qspi_set_read_cmd_format(flash, SFUD_CMD_QUAD_IO_READ_DATA, 1, 4, 6, 4); + } else if (read_mode & QUAD_OUTPUT) { + qspi_set_read_cmd_format(flash, SFUD_CMD_QUAD_OUTPUT_READ_DATA, 1, 1, 8, 4); + } else { + qspi_set_read_cmd_format(flash, SFUD_CMD_READ_DATA, 1, 1, 0, 1); + } + break; + } + + return result; +} +#endif /* SFUD_USING_QSPI */ + /** * hardware initialize */ static sfud_err hardware_init(sfud_flash *flash) { - extern sfud_err sfud_spi_port_init(sfud_flash *flash); + extern sfud_err sfud_spi_port_init(sfud_flash * flash); sfud_err result = SFUD_SUCCESS; size_t i; @@ -162,6 +256,11 @@ static sfud_err hardware_init(sfud_flash *flash) { return result; } +#ifdef SFUD_USING_QSPI + /* set default read instruction */ + flash->read_cmd_format.instruction = SFUD_CMD_READ_DATA; +#endif /* SFUD_USING_QSPI */ + /* SPI write read function must be initialize */ SFUD_ASSERT(flash->spi.wr); /* if the user don't configure flash chip information then using SFDP parameter or static flash parameter table */ @@ -315,10 +414,17 @@ sfud_err sfud_read(const sfud_flash *flash, uint32_t addr, size_t size, uint8_t result = wait_busy(flash); if (result == SFUD_SUCCESS) { - cmd_data[0] = SFUD_CMD_READ_DATA; - make_adress_byte_array(flash, addr, &cmd_data[1]); - cmd_size = flash->addr_in_4_byte ? 5 : 4; - result = spi->wr(spi, cmd_data, cmd_size, data, size); +#ifdef SFUD_USING_QSPI + if (flash->read_cmd_format.instruction != SFUD_CMD_READ_DATA) { + result = spi->qspi_read(spi, addr, (sfud_qspi_read_cmd_format *)&flash->read_cmd_format, data, size); + } else +#endif + { + cmd_data[0] = SFUD_CMD_READ_DATA; + make_adress_byte_array(flash, addr, &cmd_data[1]); + cmd_size = flash->addr_in_4_byte ? 5 : 4; + result = spi->wr(spi, cmd_data, cmd_size, data, size); + } } /* unlock SPI */ if (spi->unlock) { @@ -328,7 +434,6 @@ sfud_err sfud_read(const sfud_flash *flash, uint32_t addr, size_t size, uint8_t return result; } - /** * erase all flash data * @@ -498,7 +603,8 @@ static sfud_err page256_or_1_byte_write(const sfud_flash *flash, uint32_t addr, const uint8_t *data) { sfud_err result = SFUD_SUCCESS; const sfud_spi *spi = &flash->spi; - uint8_t cmd_data[5 + SFUD_WRITE_MAX_PAGE_SIZE], cmd_size; + static uint8_t cmd_data[5 + SFUD_WRITE_MAX_PAGE_SIZE]; + uint8_t cmd_size; size_t data_size; SFUD_ASSERT(flash); @@ -715,8 +821,16 @@ static sfud_err reset(const sfud_flash *flash) { SFUD_ASSERT(flash); cmd_data[0] = SFUD_CMD_ENABLE_RESET; + result = spi->wr(spi, cmd_data, 1, NULL, 0); + if (result == SFUD_SUCCESS) { + result = wait_busy(flash); + } else { + SFUD_INFO("Error: Flash device reset failed."); + return result; + } + cmd_data[1] = SFUD_CMD_RESET; - result = spi->wr(spi, cmd_data, 2, NULL, 0); + result = spi->wr(spi, &cmd_data[1], 1, NULL, 0); if (result == SFUD_SUCCESS) { result = wait_busy(flash); diff --git a/components/drivers/spi/spi_core.c b/components/drivers/spi/spi_core.c index 9e404d7c9480b1cdafeee2d8564c72d1b3eeee0a..64b0d2e4964482c6d0657f3af66eda20af40e737 100644 --- a/components/drivers/spi/spi_core.c +++ b/components/drivers/spi/spi_core.c @@ -34,6 +34,8 @@ rt_err_t rt_spi_bus_register(struct rt_spi_bus *bus, bus->ops = ops; /* initialize owner */ bus->owner = RT_NULL; + /* set bus mode */ + bus->mode = RT_SPI_BUS_MODE_SPI; return RT_EOK; } diff --git a/components/drivers/spi/spi_flash_sfud.c b/components/drivers/spi/spi_flash_sfud.c index e622527d7a9ec6082a32c8130d9c0b2ab8a74288..c8ff8f1b3bff69cd8ec42c7d8c7dffc4fd2d95e1 100644 --- a/components/drivers/spi/spi_flash_sfud.c +++ b/components/drivers/spi/spi_flash_sfud.c @@ -23,11 +23,21 @@ #ifndef RT_SFUD_DEFAULT_SPI_CFG /* read the JEDEC SFDP command must run at 50 MHz or less */ -#define RT_SFUD_DEFAULT_SPI_CFG \ -{ \ - .mode = RT_SPI_MODE_0 | RT_SPI_MSB, \ - .data_width = 8, \ - .max_hz = 50 * 1000 * 1000, \ +#define RT_SFUD_DEFAULT_SPI_CFG \ +{ \ + .mode = RT_SPI_MODE_0 | RT_SPI_MSB, \ + .data_width = 8, \ + .max_hz = 50 * 1000 * 1000, \ +} +#endif + +#ifdef SFUD_USING_QSPI +#define RT_SFUD_DEFAULT_QSPI_CFG \ +{ \ + RT_SFUD_DEFAULT_SPI_CFG, \ + .medium_size = 0x800000, \ + .ddr_mode = 0, \ + .qspi_dl_width = 4, \ } #endif @@ -116,31 +126,90 @@ static sfud_err spi_write_read(const sfud_spi *spi, const uint8_t *write_buf, si sfud_err result = SFUD_SUCCESS; sfud_flash *sfud_dev = (sfud_flash *) (spi->user_data); struct spi_flash_device *rtt_dev = (struct spi_flash_device *) (sfud_dev->user_data); - +#ifdef SFUD_USING_QSPI + struct rt_qspi_device *qspi_dev = RT_NULL; +#endif if (write_size) { RT_ASSERT(write_buf); } if (read_size) { RT_ASSERT(read_buf); } - - if (write_size && read_size) { - if (rt_spi_send_then_recv(rtt_dev->rt_spi_device, write_buf, write_size, read_buf, read_size) != RT_EOK) { - result = SFUD_ERR_TIMEOUT; - } - } else if (write_size) { - if (rt_spi_send(rtt_dev->rt_spi_device, write_buf, write_size) == 0) { - result = SFUD_ERR_TIMEOUT; +#ifdef SFUD_USING_QSPI + if(rtt_dev->rt_spi_device->bus->mode & RT_SPI_BUS_MODE_QSPI) { + qspi_dev = (struct rt_qspi_device *) (rtt_dev->rt_spi_device); + if (write_size && read_size) { + if (rt_qspi_send_then_recv(qspi_dev, write_buf, write_size, read_buf, read_size) == 0) { + result = SFUD_ERR_TIMEOUT; + } + } else if (write_size) { + if (rt_qspi_send(qspi_dev, write_buf, write_size) == 0) { + result = SFUD_ERR_TIMEOUT; + } } - } else { - if (rt_spi_recv(rtt_dev->rt_spi_device, read_buf, read_size) == 0) { - result = SFUD_ERR_TIMEOUT; + } + else +#endif + { + if (write_size && read_size) { + if (rt_spi_send_then_recv(rtt_dev->rt_spi_device, write_buf, write_size, read_buf, read_size) != RT_EOK) { + result = SFUD_ERR_TIMEOUT; + } + } else if (write_size) { + if (rt_spi_send(rtt_dev->rt_spi_device, write_buf, write_size) == 0) { + result = SFUD_ERR_TIMEOUT; + } + } else { + if (rt_spi_recv(rtt_dev->rt_spi_device, read_buf, read_size) == 0) { + result = SFUD_ERR_TIMEOUT; + } } } return result; } +#ifdef SFUD_USING_QSPI +/** + * QSPI fast read data + */ +static sfud_err qspi_read(const struct __sfud_spi *spi, uint32_t addr, sfud_qspi_read_cmd_format *qspi_read_cmd_format, uint8_t *read_buf, size_t read_size) { + struct rt_qspi_message message; + sfud_err result = SFUD_SUCCESS; + + sfud_flash *sfud_dev = (sfud_flash *) (spi->user_data); + struct spi_flash_device *rtt_dev = (struct spi_flash_device *) (sfud_dev->user_data); + struct rt_qspi_device *qspi_dev = (struct rt_qspi_device *) (rtt_dev->rt_spi_device); + + /* set message struct */ + message.instruction.content = qspi_read_cmd_format->instruction; + message.instruction.qspi_lines = qspi_read_cmd_format->instruction_lines; + + message.address.content = addr; + message.address.size = qspi_read_cmd_format->address_size; + message.address.qspi_lines = qspi_read_cmd_format->address_lines; + + message.alternate_bytes.content = 0; + message.alternate_bytes.size = 0; + message.alternate_bytes.qspi_lines = 0; + + message.dummy_cycles = qspi_read_cmd_format->dummy_cycles; + + message.parent.send_buf = RT_NULL; + message.parent.recv_buf = read_buf; + message.parent.length = read_size; + message.parent.cs_release = 1; + message.parent.cs_take = 1; + message.qspi_data_lines = qspi_read_cmd_format->data_lines; + + if (rt_qspi_transfer_message(qspi_dev, &message) != read_size) { + result = SFUD_ERR_TIMEOUT; + } + + return result; +} +#endif + static void spi_lock(const sfud_spi *spi) { sfud_flash *sfud_dev = (sfud_flash *) (spi->user_data); struct spi_flash_device *rtt_dev = (struct spi_flash_device *) (sfud_dev->user_data); @@ -203,6 +272,9 @@ sfud_err sfud_spi_port_init(sfud_flash *flash) { /* port SPI device interface */ flash->spi.wr = spi_write_read; +#ifdef SFUD_USING_QSPI + flash->spi.qspi_read = qspi_read; +#endif flash->spi.lock = spi_lock; flash->spi.unlock = spi_unlock; flash->spi.user_data = flash; @@ -213,8 +285,7 @@ sfud_err sfud_spi_port_init(sfud_flash *flash) { flash->retry.delay = retry_delay_100us; /* 60 seconds timeout */ flash->retry.times = 60 * 10000; - - + return result; } @@ -246,6 +317,10 @@ rt_spi_flash_device_t rt_sfud_flash_probe(const char *spi_flash_dev_name, const * @note you also can change the SPI to other configuration after initialized finish */ struct rt_spi_configuration cfg = RT_SFUD_DEFAULT_SPI_CFG; extern sfud_err sfud_device_init(sfud_flash *flash); +#ifdef SFUD_USING_QSPI + struct rt_qspi_configuration qspi_cfg = RT_SFUD_DEFAULT_QSPI_CFG; + struct rt_qspi_device *qspi_dev = RT_NULL; +#endif RT_ASSERT(spi_flash_dev_name); RT_ASSERT(spi_dev_name); @@ -277,7 +352,17 @@ rt_spi_flash_device_t rt_sfud_flash_probe(const char *spi_flash_dev_name, const goto error; } sfud_dev->spi.name = spi_dev_name_bak; - rt_spi_configure(rtt_dev->rt_spi_device, &cfg); + +#ifdef SFUD_USING_QSPI + /* set the qspi line number and configure the QSPI bus */ + if(rtt_dev->rt_spi_device->bus->mode &RT_SPI_BUS_MODE_QSPI) { + qspi_dev = (struct rt_qspi_device *)rtt_dev->rt_spi_device; + qspi_cfg.qspi_dl_width = qspi_dev->config.qspi_dl_width; + rt_qspi_configure(qspi_dev, &qspi_cfg); + } + else +#endif + rt_spi_configure(rtt_dev->rt_spi_device, &cfg); } /* SFUD flash device initialize */ { @@ -296,6 +381,17 @@ rt_spi_flash_device_t rt_sfud_flash_probe(const char *spi_flash_dev_name, const rtt_dev->geometry.sector_count = sfud_dev->chip.capacity / sfud_dev->chip.erase_gran; rtt_dev->geometry.bytes_per_sector = sfud_dev->chip.erase_gran; rtt_dev->geometry.block_size = sfud_dev->chip.erase_gran; +#ifdef SFUD_USING_QSPI + /* reconfigure the QSPI bus for medium size */ + if(rtt_dev->rt_spi_device->bus->mode &RT_SPI_BUS_MODE_QSPI) { + qspi_cfg.medium_size = sfud_dev->chip.capacity; + rt_qspi_configure(qspi_dev, &qspi_cfg); + if(qspi_dev->enter_qspi_mode != RT_NULL) + qspi_dev->enter_qspi_mode(qspi_dev); + } + /* set data lines width */ + sfud_qspi_fast_read_enable(sfud_dev, qspi_dev->config.qspi_dl_width); +#endif /* SFUD_USING_QSPI */ } /* register device */ @@ -402,14 +498,17 @@ static void sf(uint8_t argc, char **argv) { } else { char *spi_dev_name = argv[2]; rtt_dev_bak = rtt_dev; + + /* delete the old SPI flash device */ + if(rtt_dev_bak) { + rt_sfud_flash_delete(rtt_dev_bak); + } + rtt_dev = rt_sfud_flash_probe("sf_cmd", spi_dev_name); if (!rtt_dev) { return; } - /* already probe then delete the old SPI flash device */ - if(rtt_dev_bak) { - rt_sfud_flash_delete(rtt_dev_bak); - } + sfud_dev = (sfud_flash_t)rtt_dev->user_data; if (sfud_dev->chip.capacity < 1024 * 1024) { rt_kprintf("%d KB %s is current selected device.\n", sfud_dev->chip.capacity / 1024, sfud_dev->name); @@ -520,7 +619,7 @@ static void sf(uint8_t argc, char **argv) { addr = 0; size = sfud_dev->chip.capacity; uint32_t start_time, time_cast; - size_t write_size = SFUD_WRITE_MAX_PAGE_SIZE, read_size = 4096; + size_t write_size = SFUD_WRITE_MAX_PAGE_SIZE, read_size = SFUD_WRITE_MAX_PAGE_SIZE; uint8_t *write_data = rt_malloc(write_size), *read_data = rt_malloc(read_size); if (write_data && read_data) { @@ -561,6 +660,13 @@ static void sf(uint8_t argc, char **argv) { } else { result = sfud_read(sfud_dev, addr + i, size - i, read_data); } + /* data check */ + if (memcmp(write_data, read_data, read_size)) + { + rt_kprintf("Data check ERROR! Please check you flash by other command.\n"); + result = SFUD_ERR_READ; + } + if (result != SFUD_SUCCESS) { break; } diff --git a/components/drivers/spi/spi_flash_sfud.h b/components/drivers/spi/spi_flash_sfud.h index 3173b9786d89d76ec6e9ec71b255cb5e7beed673..af1ed58790c16efc9a552fdadaebe530e1fbcae7 100644 --- a/components/drivers/spi/spi_flash_sfud.h +++ b/components/drivers/spi/spi_flash_sfud.h @@ -12,6 +12,7 @@ #define _SPI_FLASH_SFUD_H_ #include +#include #include "./sfud/inc/sfud.h" #include "spi_flash.h" diff --git a/components/drivers/spi/spi_msd.c b/components/drivers/spi/spi_msd.c index ed121e184decbc0a8b93bb18aa786572e8a9763b..a109fd94888e58e776c3f931e2a88e0db5bc8309 100644 --- a/components/drivers/spi/spi_msd.c +++ b/components/drivers/spi/spi_msd.c @@ -37,8 +37,6 @@ static struct msd_device _msd_device; static rt_bool_t rt_tick_timeout(rt_tick_t tick_start, rt_tick_t tick_long); static rt_err_t MSD_take_owner(struct rt_spi_device *spi_device); -static void MSD_take_cs(struct rt_spi_device *device); -static void MSD_release_cs(struct rt_spi_device *device); static rt_err_t _wait_token(struct rt_spi_device *device, uint8_t token); static rt_err_t _wait_ready(struct rt_spi_device *device); @@ -73,36 +71,6 @@ static rt_err_t MSD_take_owner(struct rt_spi_device *spi_device) return result; } -static void MSD_take_cs(struct rt_spi_device *device) -{ - struct rt_spi_message message; - - /* initial message */ - message.send_buf = RT_NULL; - message.recv_buf = RT_NULL; - message.length = 0; - message.cs_take = 1; - message.cs_release = 0; - - /* transfer message */ - device->bus->ops->xfer(device, &message); -} - -static void MSD_release_cs(struct rt_spi_device *device) -{ - struct rt_spi_message message; - - /* initial message */ - message.send_buf = RT_NULL; - message.recv_buf = RT_NULL; - message.length = 0; - message.cs_take = 0; - message.cs_release = 1; - - /* transfer message */ - device->bus->ops->xfer(device, &message); -} - static rt_bool_t rt_tick_timeout(rt_tick_t tick_start, rt_tick_t tick_long) { rt_tick_t tick_end = tick_start + tick_long; @@ -517,7 +485,7 @@ static rt_err_t rt_msd_init(rt_device_t dev) goto _exit; } - MSD_release_cs(msd->spi_device); + rt_spi_release(msd->spi_device); /* The host shall supply power to the card so that the voltage is reached to Vdd_min within 250ms and start to supply at least 74 SD clocks to the SD card with keeping CMD line to high. @@ -542,9 +510,9 @@ static rt_err_t rt_msd_init(rt_device_t dev) while (1) { - MSD_take_cs(msd->spi_device); + rt_spi_take(msd->spi_device); result = _send_cmd(msd->spi_device, GO_IDLE_STATE, 0x00, 0x95, response_r1, response); - MSD_release_cs(msd->spi_device); + rt_spi_release(msd->spi_device); if ((result == RT_EOK) && (response[0] == MSD_IN_IDLE_STATE)) { @@ -568,9 +536,9 @@ static rt_err_t rt_msd_init(rt_device_t dev) do { - MSD_take_cs(msd->spi_device); + rt_spi_take(msd->spi_device); result = _send_cmd(msd->spi_device, SEND_IF_COND, 0x01AA, 0x87, response_r7, response); - MSD_release_cs(msd->spi_device); + rt_spi_release(msd->spi_device); if (result == RT_EOK) { @@ -622,23 +590,23 @@ static rt_err_t rt_msd_init(rt_device_t dev) /* try SD Ver1.x */ while (1) { - MSD_take_cs(msd->spi_device); + rt_spi_take(msd->spi_device); result = _send_cmd(msd->spi_device, READ_OCR, 0x00, 0x00, response_r3, response); if (result != RT_EOK) { - MSD_release_cs(msd->spi_device); + rt_spi_release(msd->spi_device); MSD_DEBUG("[info] It maybe SD1.x or MMC But it is Not response to CMD58!\r\n"); goto _exit; } if (0 != (response[0] & 0xFE)) { - MSD_release_cs(msd->spi_device); + rt_spi_release(msd->spi_device); MSD_DEBUG("[info] It look CMD58 as illegal command so it is not SD card!\r\n"); break; } - MSD_release_cs(msd->spi_device); + rt_spi_release(msd->spi_device); OCR = response[1]; OCR = (OCR << 8) + response[2]; @@ -661,24 +629,24 @@ static rt_err_t rt_msd_init(rt_device_t dev) { if (rt_tick_timeout(tick_start, rt_tick_from_millisecond(CARD_TRY_TIMES_ACMD41))) { - MSD_release_cs(msd->spi_device); + rt_spi_release(msd->spi_device); MSD_DEBUG("[info] try CMD55 + ACMD41 timeout! mabey MMC card!\r\n"); break; } - MSD_take_cs(msd->spi_device); + rt_spi_take(msd->spi_device); /* CMD55 APP_CMD */ result = _send_cmd(msd->spi_device, APP_CMD, 0x00, 0x00, response_r1, response); if (result != RT_EOK) { - MSD_release_cs(msd->spi_device); + rt_spi_release(msd->spi_device); continue; } if (0 != (response[0] & 0xFE)) { - MSD_release_cs(msd->spi_device); + rt_spi_release(msd->spi_device); MSD_DEBUG("[info] Not SD card2 , may be MMC\r\n"); break; } @@ -687,20 +655,20 @@ static rt_err_t rt_msd_init(rt_device_t dev) result = _send_cmd(msd->spi_device, SD_SEND_OP_COND, 0x00, 0x00, response_r1, response); if (result != RT_EOK) { - MSD_release_cs(msd->spi_device); + rt_spi_release(msd->spi_device); continue; } if (0 != (response[0] & 0xFE)) { - MSD_release_cs(msd->spi_device); + rt_spi_release(msd->spi_device); MSD_DEBUG("[info] Not SD card4 , may be MMC\r\n"); break; } if (0 == (response[0] & 0xFF)) { - MSD_release_cs(msd->spi_device); + rt_spi_release(msd->spi_device); is_sd_v1_x = RT_TRUE; MSD_DEBUG("[info] It is Ver1.X SD Memory Card!!!\r\n"); break; @@ -716,7 +684,7 @@ static rt_err_t rt_msd_init(rt_device_t dev) uint32_t i; MSD_DEBUG("[info] try MMC card!\r\n"); - MSD_release_cs(msd->spi_device); + rt_spi_release(msd->spi_device); /* send dummy clock */ { @@ -740,9 +708,9 @@ static rt_err_t rt_msd_init(rt_device_t dev) tick_start = rt_tick_get(); while (1) { - MSD_take_cs(msd->spi_device); + rt_spi_take(msd->spi_device); result = _send_cmd(msd->spi_device, GO_IDLE_STATE, 0x00, 0x95, response_r1, response); - MSD_release_cs(msd->spi_device); + rt_spi_release(msd->spi_device); if ((result == RT_EOK) && (response[0] == MSD_IN_IDLE_STATE)) { @@ -761,9 +729,9 @@ static rt_err_t rt_msd_init(rt_device_t dev) tick_start = rt_tick_get(); while (1) { - MSD_take_cs(msd->spi_device); + rt_spi_take(msd->spi_device); result = _send_cmd(msd->spi_device, SEND_OP_COND, 0x00, 0x00, response_r1, response); - MSD_release_cs(msd->spi_device); + rt_spi_release(msd->spi_device); if ((result == RT_EOK) && (response[0] == MSD_RESPONSE_NO_ERROR)) { @@ -783,25 +751,25 @@ static rt_err_t rt_msd_init(rt_device_t dev) } else if (msd->card_type == MSD_CARD_TYPE_SD_V2_X) { - MSD_take_cs(msd->spi_device); + rt_spi_take(msd->spi_device); result = _send_cmd(msd->spi_device, READ_OCR, 0x00, 0x00, response_r3, response); if (result != RT_EOK) { - MSD_release_cs(msd->spi_device); + rt_spi_release(msd->spi_device); MSD_DEBUG("[err] It maybe SD2.0 But it is Not response to CMD58!\r\n"); goto _exit; } if ((response[0] & 0xFE) != 0) { - MSD_release_cs(msd->spi_device); + rt_spi_release(msd->spi_device); MSD_DEBUG("[err] It look CMD58 as illegal command so it is not SD card!\r\n"); result = RT_ERROR; goto _exit; } - MSD_release_cs(msd->spi_device); + rt_spi_release(msd->spi_device); OCR = response[1]; OCR = (OCR << 8) + response[2]; @@ -822,10 +790,10 @@ static rt_err_t rt_msd_init(rt_device_t dev) /* try CMD55 + ACMD41 */ do { - MSD_take_cs(msd->spi_device); + rt_spi_take(msd->spi_device); if (rt_tick_timeout(tick_start, rt_tick_from_millisecond(CARD_TRY_TIMES_ACMD41))) { - MSD_release_cs(msd->spi_device); + rt_spi_release(msd->spi_device); MSD_DEBUG("[err] SD Ver2.x or later try CMD55 + ACMD41 timeout!\r\n"); result = RT_ERROR; goto _exit; @@ -836,13 +804,13 @@ static rt_err_t rt_msd_init(rt_device_t dev) // if((result != RT_EOK) || (response[0] == 0x01)) if (result != RT_EOK) { - MSD_release_cs(msd->spi_device); + rt_spi_release(msd->spi_device); continue; } if ((response[0] & 0xFE) != 0) { - MSD_release_cs(msd->spi_device); + rt_spi_release(msd->spi_device); MSD_DEBUG("[err] Not SD ready!\r\n"); result = RT_ERROR; goto _exit; @@ -852,7 +820,7 @@ static rt_err_t rt_msd_init(rt_device_t dev) result = _send_cmd(msd->spi_device, SD_SEND_OP_COND, 0x40000000, 0x77, response_r1, response); if (result != RT_EOK) { - MSD_release_cs(msd->spi_device); + rt_spi_release(msd->spi_device); MSD_DEBUG("[err] ACMD41 fail!\r\n"); result = RT_ERROR; goto _exit; @@ -860,33 +828,33 @@ static rt_err_t rt_msd_init(rt_device_t dev) if ((response[0] & 0xFE) != 0) { - MSD_release_cs(msd->spi_device); + rt_spi_release(msd->spi_device); MSD_DEBUG("[info] Not SD card4 , response : 0x%02X\r\n", response[0]); // break; } } while (response[0] != MSD_RESPONSE_NO_ERROR); - MSD_release_cs(msd->spi_device); + rt_spi_release(msd->spi_device); /* try CMD55 + ACMD41 */ /* --Read OCR again */ - MSD_take_cs(msd->spi_device); + rt_spi_take(msd->spi_device); result = _send_cmd(msd->spi_device, READ_OCR, 0x00, 0x00, response_r3, response); if (result != RT_EOK) { - MSD_release_cs(msd->spi_device); + rt_spi_release(msd->spi_device); MSD_DEBUG("[err] It maybe SD2.0 But it is Not response to 2nd CMD58!\r\n"); goto _exit; } if ((response[0] & 0xFE) != 0) { - MSD_release_cs(msd->spi_device); + rt_spi_release(msd->spi_device); MSD_DEBUG("[err] It look 2nd CMD58 as illegal command so it is not SD card!\r\n"); result = RT_ERROR; goto _exit; } - MSD_release_cs(msd->spi_device); + rt_spi_release(msd->spi_device); OCR = response[1]; OCR = (OCR << 8) + response[2]; @@ -933,14 +901,14 @@ static rt_err_t rt_msd_init(rt_device_t dev) /* set CRC */ { - MSD_release_cs(msd->spi_device); - MSD_take_cs(msd->spi_device); + rt_spi_release(msd->spi_device); + rt_spi_take(msd->spi_device); #ifdef MSD_USE_CRC result = _send_cmd(msd->spi_device, CRC_ON_OFF, 0x01, 0x83, response_r1, response); #else result = _send_cmd(msd->spi_device, CRC_ON_OFF, 0x00, 0x91, response_r1, response); #endif - MSD_release_cs(msd->spi_device); + rt_spi_release(msd->spi_device); if ((result != RT_EOK) || (response[0] != MSD_RESPONSE_NO_ERROR)) { MSD_DEBUG("[err] CMD59 CRC_ON_OFF fail! response : 0x%02X\r\n", response[0]); @@ -951,10 +919,10 @@ static rt_err_t rt_msd_init(rt_device_t dev) /* CMD16 SET_BLOCKLEN */ { - MSD_release_cs(msd->spi_device); - MSD_take_cs(msd->spi_device); + rt_spi_release(msd->spi_device); + rt_spi_take(msd->spi_device); result = _send_cmd(msd->spi_device, SET_BLOCKLEN, SECTOR_SIZE, 0x00, response_r1, response); - MSD_release_cs(msd->spi_device); + rt_spi_release(msd->spi_device); if ((result != RT_EOK) || (response[0] != MSD_RESPONSE_NO_ERROR)) { MSD_DEBUG("[err] CMD16 SET_BLOCKLEN fail! response : 0x%02X\r\n", response[0]); @@ -969,27 +937,27 @@ static rt_err_t rt_msd_init(rt_device_t dev) { uint8_t CSD_buffer[MSD_CSD_LEN]; - MSD_take_cs(msd->spi_device); + rt_spi_take(msd->spi_device); // result = _send_cmd(msd->spi_device, SEND_CSD, 0x00, 0xAF, response_r1, response); result = _send_cmd(msd->spi_device, SEND_CSD, 0x00, 0x00, response_r1, response); if (result != RT_EOK) { - MSD_release_cs(msd->spi_device); + rt_spi_release(msd->spi_device); MSD_DEBUG("[err] CMD9 SEND_CSD timeout!\r\n"); goto _exit; } if ((result != RT_EOK) || (response[0] != MSD_RESPONSE_NO_ERROR)) { - MSD_release_cs(msd->spi_device); + rt_spi_release(msd->spi_device); MSD_DEBUG("[err] CMD9 SEND_CSD fail! response : 0x%02X\r\n", response[0]); result = RT_ERROR; goto _exit; } result = _read_block(msd->spi_device, CSD_buffer, MSD_CSD_LEN); - MSD_release_cs(msd->spi_device); + rt_spi_release(msd->spi_device); if (result != RT_EOK) { MSD_DEBUG("[err] read CSD fail!\r\n"); @@ -1214,12 +1182,11 @@ static rt_err_t rt_msd_init(rt_device_t dev) cfg.data_width = 8; cfg.mode = RT_SPI_MODE_0 | RT_SPI_MSB; /* SPI Compatible Modes 0 */ cfg.max_hz = msd->max_clock; - rt_spi_configure(msd->spi_device, &cfg); } /* config spi */ _exit: - MSD_release_cs(msd->spi_device); + rt_spi_release(msd->spi_device); rt_mutex_release(&(msd->spi_device->bus->lock)); return result; } @@ -1249,20 +1216,10 @@ static rt_size_t rt_msd_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_siz goto _exit; } - /* config spi to high speed */ - { - struct rt_spi_configuration cfg; - cfg.data_width = 8; - cfg.mode = RT_SPI_MODE_0 | RT_SPI_MSB; /* SPI Compatible Modes 0 */ - cfg.max_hz = msd->max_clock; - - rt_spi_configure(msd->spi_device, &cfg); - } /* config spi */ - /* SINGLE_BLOCK? */ if (size == 1) { - MSD_take_cs(msd->spi_device); + rt_spi_take(msd->spi_device); result = _send_cmd(msd->spi_device, READ_SINGLE_BLOCK, pos * msd->geometry.bytes_per_sector, 0x00, response_r1, response); if ((result != RT_EOK) || (response[0] != MSD_RESPONSE_NO_ERROR)) @@ -1283,7 +1240,7 @@ static rt_size_t rt_msd_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_siz { uint32_t i; - MSD_take_cs(msd->spi_device); + rt_spi_take(msd->spi_device); result = _send_cmd(msd->spi_device, READ_MULTIPLE_BLOCK, pos * msd->geometry.bytes_per_sector, 0x00, response_r1, response); if ((result != RT_EOK) || (response[0] != MSD_RESPONSE_NO_ERROR)) @@ -1316,7 +1273,7 @@ static rt_size_t rt_msd_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_siz _exit: /* release and exit */ - MSD_release_cs(msd->spi_device); + rt_spi_release(msd->spi_device); rt_mutex_release(&(msd->spi_device->bus->lock)); return size; @@ -1335,20 +1292,10 @@ static rt_size_t rt_msd_sdhc_read(rt_device_t dev, rt_off_t pos, void *buffer, r goto _exit; } - /* config spi to high speed */ - { - struct rt_spi_configuration cfg; - cfg.data_width = 8; - cfg.mode = RT_SPI_MODE_0 | RT_SPI_MSB; /* SPI Compatible Modes 0 */ - cfg.max_hz = msd->max_clock; - - rt_spi_configure(msd->spi_device, &cfg); - } /* config spi */ - /* SINGLE_BLOCK? */ if (size == 1) { - MSD_take_cs(msd->spi_device); + rt_spi_take(msd->spi_device); result = _send_cmd(msd->spi_device, READ_SINGLE_BLOCK, pos, 0x00, response_r1, response); if ((result != RT_EOK) || (response[0] != MSD_RESPONSE_NO_ERROR)) @@ -1369,7 +1316,7 @@ static rt_size_t rt_msd_sdhc_read(rt_device_t dev, rt_off_t pos, void *buffer, r { uint32_t i; - MSD_take_cs(msd->spi_device); + rt_spi_take(msd->spi_device); result = _send_cmd(msd->spi_device, READ_MULTIPLE_BLOCK, pos, 0x00, response_r1, response); if ((result != RT_EOK) || (response[0] != MSD_RESPONSE_NO_ERROR)) @@ -1402,7 +1349,7 @@ static rt_size_t rt_msd_sdhc_read(rt_device_t dev, rt_off_t pos, void *buffer, r _exit: /* release and exit */ - MSD_release_cs(msd->spi_device); + rt_spi_release(msd->spi_device); rt_mutex_release(&(msd->spi_device->bus->lock)); return size; @@ -1422,20 +1369,11 @@ static rt_size_t rt_msd_write(rt_device_t dev, rt_off_t pos, const void *buffer, goto _exit; } - /* config spi to high speed */ - { - struct rt_spi_configuration cfg; - cfg.data_width = 8; - cfg.mode = RT_SPI_MODE_0 | RT_SPI_MSB; /* SPI Compatible Modes 0 */ - cfg.max_hz = msd->max_clock; - - rt_spi_configure(msd->spi_device, &cfg); - } /* config spi */ /* SINGLE_BLOCK? */ if (size == 1) { - MSD_take_cs(msd->spi_device); + rt_spi_take(msd->spi_device); result = _send_cmd(msd->spi_device, WRITE_BLOCK, pos * msd->geometry.bytes_per_sector, 0x00, response_r1, response); if ((result != RT_EOK) || (response[0] != MSD_RESPONSE_NO_ERROR)) { @@ -1456,7 +1394,7 @@ static rt_size_t rt_msd_write(rt_device_t dev, rt_off_t pos, const void *buffer, struct rt_spi_message message; uint32_t i; - MSD_take_cs(msd->spi_device); + rt_spi_take(msd->spi_device); #ifdef MSD_USE_PRE_ERASED if (msd->card_type != MSD_CARD_TYPE_MMC) @@ -1531,7 +1469,7 @@ static rt_size_t rt_msd_write(rt_device_t dev, rt_off_t pos, const void *buffer, _exit: /* release and exit */ - MSD_release_cs(msd->spi_device); + rt_spi_release(msd->spi_device); rt_mutex_release(&(msd->spi_device->bus->lock)); return size; @@ -1550,20 +1488,10 @@ static rt_size_t rt_msd_sdhc_write(rt_device_t dev, rt_off_t pos, const void *bu goto _exit; } - /* config spi to high speed */ - { - struct rt_spi_configuration cfg; - cfg.data_width = 8; - cfg.mode = RT_SPI_MODE_0 | RT_SPI_MSB; /* SPI Compatible Modes 0 */ - cfg.max_hz = msd->max_clock; - - rt_spi_configure(msd->spi_device, &cfg); - } /* config spi */ - /* SINGLE_BLOCK? */ if (size == 1) { - MSD_take_cs(msd->spi_device); + rt_spi_take(msd->spi_device); result = _send_cmd(msd->spi_device, WRITE_BLOCK, pos, 0x00, response_r1, response); if ((result != RT_EOK) || (response[0] != MSD_RESPONSE_NO_ERROR)) { @@ -1584,7 +1512,7 @@ static rt_size_t rt_msd_sdhc_write(rt_device_t dev, rt_off_t pos, const void *bu struct rt_spi_message message; uint32_t i; - MSD_take_cs(msd->spi_device); + rt_spi_take(msd->spi_device); #ifdef MSD_USE_PRE_ERASED /* CMD55 APP_CMD */ @@ -1655,7 +1583,7 @@ static rt_size_t rt_msd_sdhc_write(rt_device_t dev, rt_off_t pos, const void *bu _exit: /* release and exit */ - MSD_release_cs(msd->spi_device); + rt_spi_release(msd->spi_device); rt_mutex_release(&(msd->spi_device->bus->lock)); return size; diff --git a/components/drivers/src/ringblk_buf.c b/components/drivers/src/ringblk_buf.c index 1a74bf1d2448462b1894d4fb9fa8c5d152b30682..74ced674fea2b8540f228ed4ae40a5a90fcc76b8 100644 --- a/components/drivers/src/ringblk_buf.c +++ b/components/drivers/src/ringblk_buf.c @@ -18,8 +18,10 @@ * @param rbb ring block buffer object * @param buf buffer * @param buf_size buffer size - * @param block_set - * @param blk_max_num + * @param block_set block set + * @param blk_max_num max block number + * + * @note When your application need align access, please make the buffer address is aligned. */ void rt_rbb_init(rt_rbb_t rbb, rt_uint8_t *buf, rt_size_t buf_size, rt_rbb_blk_t block_set, rt_size_t blk_max_num) { @@ -123,6 +125,8 @@ static rt_rbb_blk_t find_empty_blk_in_set(rt_rbb_t rbb) * @param rbb ring block buffer object * @param blk_size block size * + * @note When your application need align access, please make the blk_szie is aligned. + * * @return != NULL: allocated block * NULL: allocate failed */ @@ -133,7 +137,7 @@ rt_rbb_blk_t rt_rbb_blk_alloc(rt_rbb_t rbb, rt_size_t blk_size) rt_rbb_blk_t head, tail, new = NULL; RT_ASSERT(rbb); - RT_ASSERT(blk_size < 1L << 24); + RT_ASSERT(blk_size < (1L << 24)); level = rt_hw_interrupt_disable(); @@ -277,6 +281,36 @@ __exit: } RTM_EXPORT(rt_rbb_blk_get); +/** + * return the block size + * + * @param block the block + * + * @return block size + */ +rt_size_t rt_rbb_blk_size(rt_rbb_blk_t block) +{ + RT_ASSERT(block); + + return block->size; +} +RTM_EXPORT(rt_rbb_blk_size); + +/** + * return the block buffer + * + * @param block the block + * + * @return block buffer + */ +rt_uint8_t *rt_rbb_blk_buf(rt_rbb_blk_t block) +{ + RT_ASSERT(block); + + return block->buf; +} +RTM_EXPORT(rt_rbb_blk_buf); + /** * free the block * diff --git a/components/drivers/usb/usbdevice/core/core.c b/components/drivers/usb/usbdevice/core/core.c index fb850d6d2b154d7305cb3b9a13edfebc645ec345..4e3a3e9280006763b823a724f3b33e1adfbf5039 100644 --- a/components/drivers/usb/usbdevice/core/core.c +++ b/components/drivers/usb/usbdevice/core/core.c @@ -194,7 +194,18 @@ static rt_err_t _get_descriptor(struct udevice* device, ureq_t setup) _get_string_descriptor(device, setup); break; case USB_DESC_TYPE_DEVICEQUALIFIER: - _get_qualifier_descriptor(device, setup); + /* If a full-speed only device (with a device descriptor version number equal to 0200H) receives a + GetDescriptor() request for a device_qualifier, it must respond with a request error. The host must not make + a request for an other_speed_configuration descriptor unless it first successfully retrieves the + device_qualifier descriptor. */ + if(device->dcd->device_is_hs) + { + _get_qualifier_descriptor(device, setup); + } + else + { + rt_usbd_ep0_set_stall(device); + } break; case USB_DESC_TYPE_OTHERSPEED: _get_config_descriptor(device, setup); diff --git a/components/drivers/wlan/wlan_dev.c b/components/drivers/wlan/wlan_dev.c index d86dfb25d350b9b0774cb1b03d886d0209c36f8a..0beac52aae4905b22f9a69f33a7d14b4badcae18 100644 --- a/components/drivers/wlan/wlan_dev.c +++ b/components/drivers/wlan/wlan_dev.c @@ -145,7 +145,10 @@ rt_err_t rt_wlan_dev_ap_start(struct rt_wlan_device *device, struct rt_wlan_info rt_memset(&ap_info, 0, sizeof(struct rt_ap_info)); rt_memcpy(&ap_info.ssid, &info->ssid, sizeof(rt_wlan_ssid_t)); - rt_memcpy(ap_info.key.val, password, password_len); + if (password != RT_NULL) + { + rt_memcpy(ap_info.key.val, password, password_len); + } ap_info.key.len = password_len; ap_info.hidden = info->hidden; ap_info.channel = info->channel; @@ -184,13 +187,21 @@ rt_err_t rt_wlan_dev_ap_deauth(struct rt_wlan_device *device, rt_uint8_t mac[6]) int rt_wlan_dev_get_rssi(struct rt_wlan_device *device) { int rssi = 0; + rt_err_t result = RT_EOK; if (device == RT_NULL) { - return -RT_EIO; + rt_set_errno(-RT_EIO); + return 0; + } + + result = rt_device_control(RT_DEVICE(device), RT_WLAN_CMD_GET_RSSI, &rssi); + if (result != RT_EOK) + { + rt_set_errno(result); + return 0; } - rt_device_control(RT_DEVICE(device), RT_WLAN_CMD_GET_RSSI, &rssi); return rssi; } @@ -235,14 +246,20 @@ rt_err_t rt_wlan_dev_set_powersave(struct rt_wlan_device *device, int level) int rt_wlan_dev_get_powersave(struct rt_wlan_device *device) { - int level = 0; + int level = -1; + rt_err_t result = RT_EOK; if (device == RT_NULL) { + rt_set_errno(-RT_EIO); return -1; } - rt_device_control(RT_DEVICE(device), RT_WLAN_CMD_GET_POWERSAVE, &level); + result = rt_device_control(RT_DEVICE(device), RT_WLAN_CMD_GET_POWERSAVE, &level); + if (result != RT_EOK) + { + rt_set_errno(result); + } return level; } @@ -432,19 +449,21 @@ rt_err_t rt_wlan_dev_set_channel(struct rt_wlan_device *device, int channel) return result; } -rt_err_t rt_wlan_dev_get_channel(struct rt_wlan_device *device) +int rt_wlan_dev_get_channel(struct rt_wlan_device *device) { rt_err_t result = RT_EOK; - int channel; + int channel = -1; if (device == RT_NULL) { - return -RT_EIO; + rt_set_errno(-RT_EIO); + return -1; } result = rt_device_control(RT_DEVICE(device), RT_WLAN_CMD_GET_CHANNEL, &channel); if (result != RT_EOK) { + rt_set_errno(result); return -1; } @@ -466,17 +485,19 @@ rt_err_t rt_wlan_dev_set_country(struct rt_wlan_device *device, rt_country_code_ rt_country_code_t rt_wlan_dev_get_country(struct rt_wlan_device *device) { - int result = 0; + int result = RT_EOK; rt_country_code_t country_code = RT_COUNTRY_UNKNOWN; if (device == RT_NULL) { - return country_code; + rt_set_errno(-RT_EIO); + return RT_COUNTRY_UNKNOWN; } result = rt_device_control(RT_DEVICE(device), RT_WLAN_CMD_GET_COUNTRY, &country_code); if (result != RT_EOK) { + rt_set_errno(result); return RT_COUNTRY_UNKNOWN; } @@ -641,7 +662,7 @@ static rt_err_t _rt_wlan_dev_control(rt_device_t dev, int cmd, void *args) LOG_D("%s %d cmd[%d]:%s run......", __FUNCTION__, __LINE__, RT_WLAN_CMD_SET_POWERSAVE, "RT_WLAN_CMD_SET_POWERSAVE"); if (wlan->ops->wlan_set_powersave) - wlan->ops->wlan_set_powersave(wlan, level); + err = wlan->ops->wlan_set_powersave(wlan, level); break; } case RT_WLAN_CMD_GET_POWERSAVE: @@ -659,7 +680,7 @@ static rt_err_t _rt_wlan_dev_control(rt_device_t dev, int cmd, void *args) LOG_D("%s %d cmd[%d]:%s run......", __FUNCTION__, __LINE__, RT_WLAN_CMD_CFG_PROMISC, "RT_WLAN_CMD_CFG_PROMISC"); if (wlan->ops->wlan_cfg_promisc) - wlan->ops->wlan_cfg_promisc(wlan, start); + err = wlan->ops->wlan_cfg_promisc(wlan, start); break; } case RT_WLAN_CMD_CFG_FILTER: @@ -668,7 +689,7 @@ static rt_err_t _rt_wlan_dev_control(rt_device_t dev, int cmd, void *args) LOG_D("%s %d cmd[%d]:%s run......", __FUNCTION__, __LINE__, RT_WLAN_CMD_CFG_FILTER, "RT_WLAN_CMD_CFG_FILTER"); if (wlan->ops->wlan_cfg_filter) - wlan->ops->wlan_cfg_filter(wlan, filter); + err = wlan->ops->wlan_cfg_filter(wlan, filter); break; } case RT_WLAN_CMD_SET_CHANNEL: @@ -676,7 +697,7 @@ static rt_err_t _rt_wlan_dev_control(rt_device_t dev, int cmd, void *args) int channel = *(int *)args; LOG_D("%s %d cmd[%d]:%s run......", __FUNCTION__, __LINE__, RT_WLAN_CMD_SET_CHANNEL, "RT_WLAN_CMD_SET_CHANNEL"); if (wlan->ops->wlan_set_channel) - wlan->ops->wlan_set_channel(wlan, channel); + err = wlan->ops->wlan_set_channel(wlan, channel); break; } case RT_WLAN_CMD_GET_CHANNEL: @@ -694,7 +715,7 @@ static rt_err_t _rt_wlan_dev_control(rt_device_t dev, int cmd, void *args) LOG_D("%s %d cmd[%d]:%s run......", __FUNCTION__, __LINE__, RT_WLAN_CMD_SET_COUNTRY, "RT_WLAN_CMD_SET_COUNTRY"); if (wlan->ops->wlan_set_country) - wlan->ops->wlan_set_country(wlan, country); + err = wlan->ops->wlan_set_country(wlan, country); break; } case RT_WLAN_CMD_GET_COUNTRY: @@ -711,7 +732,7 @@ static rt_err_t _rt_wlan_dev_control(rt_device_t dev, int cmd, void *args) LOG_D("%s %d cmd[%d]:%s run......", __FUNCTION__, __LINE__, RT_WLAN_CMD_SET_MAC, "RT_WLAN_CMD_SET_MAC"); if (wlan->ops->wlan_set_mac) - wlan->ops->wlan_set_mac(wlan, mac); + err = wlan->ops->wlan_set_mac(wlan, mac); break; } case RT_WLAN_CMD_GET_MAC: @@ -720,7 +741,7 @@ static rt_err_t _rt_wlan_dev_control(rt_device_t dev, int cmd, void *args) LOG_D("%s %d cmd[%d]:%s run......", __FUNCTION__, __LINE__, RT_WLAN_CMD_GET_MAC, "RT_WLAN_CMD_GET_MAC"); if (wlan->ops->wlan_get_mac) - wlan->ops->wlan_get_mac(wlan, mac); + err = wlan->ops->wlan_get_mac(wlan, mac); break; } default: @@ -733,22 +754,16 @@ static rt_err_t _rt_wlan_dev_control(rt_device_t dev, int cmd, void *args) return err; } -struct rt_wlan_device *rt_wlan_dev_register(const char *name, const struct rt_wlan_dev_ops *ops, rt_uint32_t flag, void *user_data) +rt_err_t rt_wlan_dev_register(struct rt_wlan_device *wlan, const char *name, const struct rt_wlan_dev_ops *ops, rt_uint32_t flag, void *user_data) { - struct rt_wlan_device *wlan; + rt_err_t err = RT_EOK; - if (name == RT_NULL || ops == RT_NULL) + if ((wlan == RT_NULL) || (name == RT_NULL) || (ops == RT_NULL)) { LOG_E("F:%s L:%d parameter Wrongful", __FUNCTION__, __LINE__); return RT_NULL; } - wlan = rt_malloc(sizeof(struct rt_wlan_device)); - if (wlan == RT_NULL) - { - LOG_E("F:%s L:%d", __FUNCTION__, __LINE__); - return RT_NULL; - } rt_memset(wlan, 0, sizeof(struct rt_wlan_device)); wlan->device.init = _rt_wlan_dev_init; @@ -765,9 +780,9 @@ struct rt_wlan_device *rt_wlan_dev_register(const char *name, const struct rt_wl wlan->user_data = user_data; wlan->flags = flag; - rt_device_register(&wlan->device, name, RT_DEVICE_FLAG_RDWR); + err = rt_device_register(&wlan->device, name, RT_DEVICE_FLAG_RDWR); LOG_D("F:%s L:%d run", __FUNCTION__, __LINE__); - return wlan; + return err; } diff --git a/components/drivers/wlan/wlan_dev.h b/components/drivers/wlan/wlan_dev.h index f46f3c001fd27f5b6f05703a5de9352b1f7dd2fc..a9300be9d79237bfe589485370065f439c0d0e5b 100644 --- a/components/drivers/wlan/wlan_dev.h +++ b/components/drivers/wlan/wlan_dev.h @@ -559,7 +559,7 @@ rt_err_t rt_wlan_dev_cfg_filter(struct rt_wlan_device *device, struct rt_wlan_fi * wlan device channel interface */ rt_err_t rt_wlan_dev_set_channel(struct rt_wlan_device *device, int channel); -rt_err_t rt_wlan_dev_get_channel(struct rt_wlan_device *device); +int rt_wlan_dev_get_channel(struct rt_wlan_device *device); /* * wlan device country interface @@ -576,7 +576,8 @@ rt_err_t rt_wlan_dev_report_data(struct rt_wlan_device *device, void *buff, int /* * wlan device register interface */ -struct rt_wlan_device *rt_wlan_dev_register(const char *name, const struct rt_wlan_dev_ops *ops, rt_uint32_t flag, void *user_data); +rt_err_t rt_wlan_dev_register(struct rt_wlan_device *wlan, const char *name, + const struct rt_wlan_dev_ops *ops, rt_uint32_t flag, void *user_data); #ifdef __cplusplus } diff --git a/components/drivers/wlan/wlan_mgnt.c b/components/drivers/wlan/wlan_mgnt.c index 1d0b0c4aa7f15f866c1c193ce6f036bb810b9a88..bdddac1fa2f2c081216195bfa38017270db85176 100644 --- a/components/drivers/wlan/wlan_mgnt.c +++ b/components/drivers/wlan/wlan_mgnt.c @@ -1320,7 +1320,10 @@ rt_err_t rt_wlan_start_ap_adv(struct rt_wlan_info *info, const char *password) return -RT_EIO; } RT_WLAN_LOG_D("%s is run", __FUNCTION__); - password_len = rt_strlen(password); + if (password != RT_NULL) + { + password_len = rt_strlen(password); + } if (password_len > RT_WLAN_PASSWORD_MAX_LENGTH) { RT_WLAN_LOG_E("key is to long! len:%d", password_len); @@ -1358,16 +1361,16 @@ rt_err_t rt_wlan_start_ap_adv(struct rt_wlan_info *info, const char *password) return err; } -int rt_wlan_ap_is_active(void) +rt_bool_t rt_wlan_ap_is_active(void) { - int _active = 0; + rt_bool_t _active = RT_FALSE; if (_ap_is_null()) { - return 0; + return RT_FALSE; } - _active = _ap_mgnt.state & RT_WLAN_STATE_ACTIVE ? 1 : 0; + _active = _ap_mgnt.state & RT_WLAN_STATE_ACTIVE ? RT_TRUE : RT_FALSE; RT_WLAN_LOG_D("%s is run active:%s", __FUNCTION__, _active ? "Active" : "Inactive"); return _active; } diff --git a/components/drivers/wlan/wlan_mgnt.h b/components/drivers/wlan/wlan_mgnt.h index d11d9ee3472d3013b7d927befa599d74831e9784..f4d9e0cff9aabcf7e5efa717a41116f283735606 100644 --- a/components/drivers/wlan/wlan_mgnt.h +++ b/components/drivers/wlan/wlan_mgnt.h @@ -97,7 +97,7 @@ int rt_wlan_get_rssi(void); */ rt_err_t rt_wlan_start_ap(const char *ssid, const char *password); rt_err_t rt_wlan_start_ap_adv(struct rt_wlan_info *info, const char *password); -int rt_wlan_ap_is_active(void); +rt_bool_t rt_wlan_ap_is_active(void); rt_err_t rt_wlan_ap_stop(void); rt_err_t rt_wlan_ap_get_info(struct rt_wlan_info *info); int rt_wlan_ap_get_sta_num(void); diff --git a/components/finsh/cmd.c b/components/finsh/cmd.c index c66f72e650938dff48a10c886f96d0e2dbce8b7c..a497af6e3154710b46df443a0fc3b40ddc8f5ff2 100644 --- a/components/finsh/cmd.c +++ b/components/finsh/cmd.c @@ -199,7 +199,7 @@ long list_sem(void) return _list_sem(&info->object_list); } -FINSH_FUNCTION_EXPORT(list_sem, list semaphone in system); +FINSH_FUNCTION_EXPORT(list_sem, list semaphore in system); MSH_CMD_EXPORT(list_sem, list semaphore in system); #endif diff --git a/components/libc/compilers/dlib/sys/errno.h b/components/libc/compilers/dlib/sys/errno.h deleted file mode 100644 index 1ecb58b74c41648b53dad5358c811406c8aa5d30..0000000000000000000000000000000000000000 --- a/components/libc/compilers/dlib/sys/errno.h +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright (c) 2006-2018, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - */ -#ifndef SYS_ERRNO_H__ -#define SYS_ERRNO_H__ - -#include - - -#endif diff --git a/components/net/Kconfig b/components/net/Kconfig index c302dec152749c34eaa6b042a4e78a690822998b..cef3ceacd3ab0d7ddc1f85accde2a79423395cf2 100644 --- a/components/net/Kconfig +++ b/components/net/Kconfig @@ -21,6 +21,11 @@ config RT_USING_SAL bool "Support AT Commands stack" default y depends on AT_USING_SOCKET + + config SAL_USING_TLS + bool "Support MbedTLS protocol" + default y + depends on PKG_USING_MBEDTLS endmenu endif diff --git a/components/net/at/at_socket/at_socket.c b/components/net/at/at_socket/at_socket.c index 01646f0d89e0699ff7894a42b8a76fb22bc2708c..3925f0f57cd8f45ee72928be4d7b119f9e0bc8a0 100644 --- a/components/net/at/at_socket/at_socket.c +++ b/components/net/at/at_socket/at_socket.c @@ -622,8 +622,20 @@ int at_recvfrom(int socket, void *mem, size_t len, int flags, struct sockaddr *f goto __exit; } sock->state = AT_SOCKET_CONNECT; + /* set AT socket receive data callback function */ + at_dev_ops->at_set_event_cb(AT_SOCKET_EVT_RECV, at_recv_notice_cb); + at_dev_ops->at_set_event_cb(AT_SOCKET_EVT_CLOSED, at_closed_notice_cb); } + /* receive packet list last transmission of remaining data */ + rt_mutex_take(sock->recv_lock, RT_WAITING_FOREVER); + if((recv_len = at_recvpkt_get(&(sock->recvpkt_list), (char *)mem, len)) > 0) + { + rt_mutex_release(sock->recv_lock); + goto __exit; + } + rt_mutex_release(sock->recv_lock); + /* socket passively closed, receive function return 0 */ if (sock->state == AT_SOCKET_CLOSED) { @@ -637,15 +649,6 @@ int at_recvfrom(int socket, void *mem, size_t len, int flags, struct sockaddr *f goto __exit; } - /* receive packet list last transmission of remaining data */ - rt_mutex_take(sock->recv_lock, RT_WAITING_FOREVER); - if((recv_len = at_recvpkt_get(&(sock->recvpkt_list), (char *)mem, len)) > 0) - { - rt_mutex_release(sock->recv_lock); - goto __exit; - } - rt_mutex_release(sock->recv_lock); - /* non-blocking sockets receive data */ if (flags & MSG_DONTWAIT) { diff --git a/components/net/sal_socket/SConscript b/components/net/sal_socket/SConscript index e9621933592c2a9b94739603948e92cb4731b2eb..cc7634f7d96aa728b160c2c5bad4cdd12cd1e4df 100644 --- a/components/net/sal_socket/SConscript +++ b/components/net/sal_socket/SConscript @@ -15,10 +15,13 @@ if GetDepend('SAL_USING_LWIP'): if GetDepend('SAL_USING_AT'): src += Glob('impl/af_inet_at.c') - + if GetDepend('SAL_USING_LWIP') or GetDepend('SAL_USING_AT'): CPPPATH += [cwd + '/impl'] +if GetDepend('SAL_USING_TLS'): + src += Glob('impl/proto_mbedtls.c') + if GetDepend('SAL_USING_POSIX'): CPPPATH += [cwd + '/include/dfs_net'] src += Glob('socket/net_sockets.c') diff --git a/components/net/sal_socket/impl/af_inet_at.c b/components/net/sal_socket/impl/af_inet_at.c index c064283a617d7e13f0c581ed8acf878583a3033c..90d1537967f60e163112fcb9a356454c9fde747d 100644 --- a/components/net/sal_socket/impl/af_inet_at.c +++ b/components/net/sal_socket/impl/af_inet_at.c @@ -62,7 +62,7 @@ static int at_poll(struct dfs_fd *file, struct rt_pollreq *req) } #endif -static const struct proto_ops at_inet_stream_ops = +static const struct sal_socket_ops at_socket_ops = { at_socket, at_closesocket, @@ -90,25 +90,30 @@ static int at_create(struct sal_socket *socket, int type, int protocol) //TODO Check type & protocol - socket->ops = &at_inet_stream_ops; + socket->ops = &at_socket_ops; return 0; } -static const struct proto_family at_inet_family_ops = { - "at", - AF_AT, - AF_INET, - at_create, +static struct sal_proto_ops at_proto_ops = +{ at_gethostbyname, NULL, - at_freeaddrinfo, at_getaddrinfo, + at_freeaddrinfo, +}; + +static const struct sal_proto_family at_inet_family = +{ + AF_AT, + AF_INET, + at_create, + &at_proto_ops, }; int at_inet_init(void) { - sal_proto_family_register(&at_inet_family_ops); + sal_proto_family_register(&at_inet_family); return 0; } diff --git a/components/net/sal_socket/impl/af_inet_lwip.c b/components/net/sal_socket/impl/af_inet_lwip.c index 9e726c87e91dcc5b4775a707aca55fcd30a36310..0826b052ab93df5e8d860d6a5112f683a87aa8b7 100644 --- a/components/net/sal_socket/impl/af_inet_lwip.c +++ b/components/net/sal_socket/impl/af_inet_lwip.c @@ -259,7 +259,8 @@ static int inet_poll(struct dfs_fd *file, struct rt_pollreq *req) } #endif -static const struct proto_ops lwip_inet_stream_ops = { +static const struct sal_socket_ops lwip_socket_ops = +{ inet_socket, lwip_close, lwip_bind, @@ -286,25 +287,30 @@ static int inet_create(struct sal_socket *socket, int type, int protocol) //TODO Check type & protocol - socket->ops = &lwip_inet_stream_ops; + socket->ops = &lwip_socket_ops; return 0; } -static const struct proto_family lwip_inet_family_ops = { - "lwip", - AF_INET, - AF_INET, - inet_create, +static struct sal_proto_ops lwip_proto_ops = +{ lwip_gethostbyname, lwip_gethostbyname_r, - lwip_freeaddrinfo, lwip_getaddrinfo, + lwip_freeaddrinfo, +}; + +static const struct sal_proto_family lwip_inet_family = +{ + AF_INET, + AF_INET, + inet_create, + &lwip_proto_ops, }; int lwip_inet_init(void) { - sal_proto_family_register(&lwip_inet_family_ops); + sal_proto_family_register(&lwip_inet_family); return 0; } diff --git a/components/net/sal_socket/impl/proto_mbedtls.c b/components/net/sal_socket/impl/proto_mbedtls.c new file mode 100644 index 0000000000000000000000000000000000000000..8ed9f67ff1cdf500f12db2e0704961b134ff1ace --- /dev/null +++ b/components/net/sal_socket/impl/proto_mbedtls.c @@ -0,0 +1,239 @@ +/* + * Copyright (c) 2006-2018, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2018-11-12 ChenYong First version + */ + +#include + +#ifdef RT_USING_DFS +#include +#endif + +#ifdef SAL_USING_TLS +#include +#endif +#include +#include + +#ifdef SAL_USING_TLS + +#if !defined(MBEDTLS_CONFIG_FILE) +#include +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include +#include + +#ifndef SAL_MEBDTLS_BUFFER_LEN +#define SAL_MEBDTLS_BUFFER_LEN 1024 +#endif + +static void *mebdtls_socket(int socket) +{ + MbedTLSSession *session = RT_NULL; + char *pers = "mbedtls"; + + if (socket < 0) + { + return RT_NULL; + } + + session = (MbedTLSSession *) tls_calloc(1, sizeof(MbedTLSSession)); + if (session == RT_NULL) + { + return RT_NULL; + } + + session->buffer_len = SAL_MEBDTLS_BUFFER_LEN; + session->buffer = tls_calloc(1, session->buffer_len); + if (session->buffer == RT_NULL) + { + tls_free(session); + session = RT_NULL; + + return RT_NULL; + } + + /* initialize TLS Client sesison */ + if (mbedtls_client_init(session, (void *) pers, rt_strlen(pers)) != RT_EOK) + { + mbedtls_client_close(session); + return RT_NULL; + } + session->server_fd.fd = socket; + + return (void *)session; +} + +int mbedtls_net_send_cb(void *ctx, const unsigned char *buf, size_t len) +{ + struct sal_socket *sock; + int socket, ret; + + RT_ASSERT(ctx); + RT_ASSERT(buf); + + socket = ((mbedtls_net_context *) ctx)->fd; + sock = sal_get_socket(socket); + if (sock == RT_NULL) + { + return -1; + } + + /* Register scoket sendto option to TLS send data callback */ + ret = sock->ops->sendto((int) sock->user_data, (void *)buf, len, 0, RT_NULL, RT_NULL); + if (ret < 0) + { +#ifdef RT_USING_DFS + if ((fcntl(socket, F_GETFL) & O_NONBLOCK) == O_NONBLOCK) + return MBEDTLS_ERR_SSL_WANT_WRITE; +#endif + if (errno == ECONNRESET) + return MBEDTLS_ERR_NET_CONN_RESET; + if ( errno == EINTR) + return MBEDTLS_ERR_SSL_WANT_READ; + + return MBEDTLS_ERR_NET_SEND_FAILED ; + } + + return ret; +} + +int mbedtls_net_recv_cb( void *ctx, unsigned char *buf, size_t len) +{ + struct sal_socket *sock; + int socket, ret; + + RT_ASSERT(ctx); + RT_ASSERT(buf); + + socket = ((mbedtls_net_context *) ctx)->fd; + sock = sal_get_socket(socket); + if (sock == RT_NULL) + { + return -1; + } + + /* Register scoket recvfrom option to TLS recv data callback */ + ret = sock->ops->recvfrom((int) sock->user_data, (void *)buf, len, 0, RT_NULL, RT_NULL); + if (ret < 0) + { +#ifdef RT_USING_DFS + if ((fcntl(socket, F_GETFL) & O_NONBLOCK) == O_NONBLOCK) + return MBEDTLS_ERR_SSL_WANT_WRITE; +#endif + if (errno == ECONNRESET) + return MBEDTLS_ERR_NET_CONN_RESET; + if ( errno == EINTR) + return MBEDTLS_ERR_SSL_WANT_READ; + + return MBEDTLS_ERR_NET_RECV_FAILED ; + } + + return ret; +} + +static int mbedtls_connect(void *sock) +{ + MbedTLSSession *session = RT_NULL; + int ret = 0; + + RT_ASSERT(sock); + + session = (MbedTLSSession *) sock; + + /* Set the SSL Configure infromation */ + ret = mbedtls_client_context(session); + if (ret < 0) + { + goto __exit; + } + + /* Set the underlying BIO callbacks for write, read and read-with-timeout. */ + mbedtls_ssl_set_bio(&session->ssl, &session->server_fd, mbedtls_net_send_cb, mbedtls_net_recv_cb, RT_NULL); + + while ((ret = mbedtls_ssl_handshake(&session->ssl)) != 0) + { + if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) + { + goto __exit; + } + } + + /* Return the result of the certificate verification */ + ret = mbedtls_ssl_get_verify_result(&session->ssl); + if (ret != 0) + { + rt_memset(session->buffer, 0x00, session->buffer_len); + mbedtls_x509_crt_verify_info((char *)session->buffer, session->buffer_len, " ! ", ret); + goto __exit; + } + + return ret; + +__exit: + if (session) + { + mbedtls_client_close(session); + } + + return ret; +} + +static int mbedtls_closesocket(void *sock) +{ + struct sal_socket *ssock; + int socket; + + if (sock == RT_NULL) + { + return 0; + } + + socket = ((MbedTLSSession *) sock)->server_fd.fd; + ssock = sal_get_socket(socket); + if (ssock == RT_NULL) + { + return -1; + } + + /* Close TLS client session, and clean user-data in SAL socket */ + mbedtls_client_close((MbedTLSSession *) sock); + ssock->user_data_tls = RT_NULL; + + return 0; +} + +static const struct sal_proto_tls_ops mbedtls_proto_ops= +{ + RT_NULL, + mebdtls_socket, + mbedtls_connect, + (int (*)(void *sock, const void *data, size_t size)) mbedtls_client_write, + (int (*)(void *sock, void *mem, size_t len)) mbedtls_client_read, + mbedtls_closesocket, +}; + +static const struct sal_proto_tls mbedtls_proto = +{ + "mbedtls", + &mbedtls_proto_ops, +}; + +int sal_mbedtls_proto_init(void) +{ + /* register MbedTLS protocol options to SAL */ + sal_proto_tls_register(&mbedtls_proto); + + return 0; +} +INIT_COMPONENT_EXPORT(sal_mbedtls_proto_init); + +#endif /* SAL_USING_TLS */ diff --git a/components/net/sal_socket/include/sal.h b/components/net/sal_socket/include/sal.h index 68248742d6822c9911af38a6bd8732eb6a02ceb5..17d44eef77b47d67f383bd65e4510928b14bd508 100644 --- a/components/net/sal_socket/include/sal.h +++ b/components/net/sal_socket/include/sal.h @@ -25,7 +25,7 @@ extern "C" { typedef uint32_t socklen_t; #endif -/* sal socket magic word */ +/* SAL socket magic word */ #define SAL_SOCKET_MAGIC 0x5A10 /* The maximum number of sockets structure */ @@ -38,12 +38,12 @@ typedef uint32_t socklen_t; #define SAL_PROTO_FAMILIES_NUM 4 #endif -/* sal socket offset */ +/* SAL socket offset */ #ifndef SAL_SOCKET_OFFSET #define SAL_SOCKET_OFFSET 0 #endif -struct proto_ops +struct sal_socket_ops { int (*socket) (int domain, int type, int protocol); int (*closesocket)(int s); @@ -64,30 +64,38 @@ struct proto_ops #endif }; +struct sal_proto_ops +{ + struct hostent* (*gethostbyname) (const char *name); + int (*gethostbyname_r)(const char *name, struct hostent *ret, char *buf, size_t buflen, struct hostent **result, int *h_errnop); + int (*getaddrinfo) (const char *nodename, const char *servname, const struct addrinfo *hints, struct addrinfo **res); + void (*freeaddrinfo) (struct addrinfo *ai); +}; + struct sal_socket { - uint32_t magic; /* sal socket magic word */ + uint32_t magic; /* SAL socket magic word */ - int socket; /* sal socket descriptor */ + int socket; /* SAL socket descriptor */ int domain; int type; int protocol; - const struct proto_ops *ops; /* socket options */ - void *user_data; /* specific sal socket data */ + const struct sal_socket_ops *ops; /* socket options */ + + void *user_data; /* user-specific data */ +#ifdef SAL_USING_TLS + void *user_data_tls; /* user-specific TLS data */ +#endif }; -struct proto_family +struct sal_proto_family { - char name[RT_NAME_MAX]; int family; /* primary protocol families type */ int sec_family; /* secondary protocol families type */ - int (*create)(struct sal_socket *sal_socket, int type, int protocol); /* register socket options */ + int (*create)(struct sal_socket *sal_socket, int type, int protocol); /* register socket options */ - struct hostent* (*gethostbyname) (const char *name); - int (*gethostbyname_r)(const char *name, struct hostent *ret, char *buf, size_t buflen, struct hostent **result, int *h_errnop); - void (*freeaddrinfo) (struct addrinfo *ai); - int (*getaddrinfo) (const char *nodename, const char *servname, const struct addrinfo *hints, struct addrinfo **res); + struct sal_proto_ops *ops; /* protocol family options */ }; /* SAL(Socket Abstraction Layer) initialize */ @@ -95,10 +103,11 @@ int sal_init(void); struct sal_socket *sal_get_socket(int sock); -/* protocol family register and unregister operate */ -int sal_proto_family_register(const struct proto_family *pf); -int sal_proto_family_unregister(const struct proto_family *pf); -struct proto_family *sal_proto_family_find(const char *name); +/* SAL protocol family register and unregister operate */ +int sal_proto_family_register(const struct sal_proto_family *pf); +int sal_proto_family_unregister(int family); +rt_bool_t sal_proto_family_is_registered(int family); +struct sal_proto_family *sal_proto_family_find(int family); #ifdef __cplusplus } diff --git a/components/net/sal_socket/include/sal_tls.h b/components/net/sal_socket/include/sal_tls.h new file mode 100644 index 0000000000000000000000000000000000000000..7681b313bdf7daf8d6c86d8a9f9263e7405c3555 --- /dev/null +++ b/components/net/sal_socket/include/sal_tls.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2006-2018, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2018-11-10 ChenYong First version + */ +#ifndef __SAL_TLS_H__ +#define __SAL_TLS_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/* Protocol level for TLS. + * Here, the same socket protocol level for TLS as in Linux was used. + */ +#define SOL_TLS 282 + +/* Socket options for TLS */ + +/* Socket option to select TLS credentials to use. */ +#define TLS_CRET_LIST 1 +/* Socket option to set select ciphersuites to use. */ +#define TLS_CIPHERSUITE_LIST 2 +/* Socket option to set peer verification level for TLS connection. */ +#define TLS_PEER_VERIFY 3 +/* Socket option to set role for DTLS connection. */ +#define TLS_DTLS_ROLE 4 + +/* Protocol numbers for TLS protocols */ +#define PROTOCOL_TLS 256 +#define PROTOCOL_DTLS 257 + + +struct sal_proto_tls_ops +{ + int (*init)(void); + void* (*socket)(int socket); + int (*connect)(void *sock); + int (*send)(void *sock, const void *data, size_t size); + int (*recv)(void *sock, void *mem, size_t len); + int (*closesocket)(void *sock); + + int (*set_cret_list)(void *sock, const void *cert, size_t size); /* Set TLS credentials */ + int (*set_ciphersurite)(void *sock, const void* ciphersurite, size_t size); /* Set select ciphersuites */ + int (*set_peer_verify)(void *sock, const void* peer_verify, size_t size); /* Set peer verification */ + int (*set_dtls_role)(void *sock, const void *dtls_role, size_t size); /* Set role for DTLS */ +}; + +struct sal_proto_tls +{ + char name[RT_NAME_MAX]; /* TLS protocol name */ + const struct sal_proto_tls_ops *ops; /* SAL TLS protocol options */ +}; + +/* SAL TLS protocol register */ +int sal_proto_tls_register(const struct sal_proto_tls *pt); + +#ifdef __cplusplus +} +#endif + +#endif /* __SAL_TLS_H__ */ diff --git a/components/net/sal_socket/include/socket/sys_socket/sys/socket.h b/components/net/sal_socket/include/socket/sys_socket/sys/socket.h index dd2c3850a6ffce225e64360b63d864830081ed50..04470aa84a522a233b3ea2e3b238a825ddc51ae8 100644 --- a/components/net/sal_socket/include/socket/sys_socket/sys/socket.h +++ b/components/net/sal_socket/include/socket/sys_socket/sys/socket.h @@ -14,6 +14,9 @@ #include #include +#ifdef SAL_USING_TLS +#include +#endif #ifdef __cplusplus extern "C" { diff --git a/components/net/sal_socket/src/sal_socket.c b/components/net/sal_socket/src/sal_socket.c index ac36cb2139e53f808d3048e5b64ef5180e307422..dba8e66254d0781c7f71df16a2e5387a330afa10 100644 --- a/components/net/sal_socket/src/sal_socket.c +++ b/components/net/sal_socket/src/sal_socket.c @@ -6,6 +6,7 @@ * Change Logs: * Date Author Notes * 2018-05-23 ChenYong First version + * 2018-11-12 ChenYong Add TLS support */ #include @@ -13,6 +14,9 @@ #include #include +#ifdef SAL_USING_TLS +#include +#endif #include #define DBG_ENABLE @@ -30,13 +34,32 @@ struct sal_socket_table struct sal_socket **sockets; }; +#ifdef SAL_USING_TLS +/* The global TLS protocol options */ +static struct sal_proto_tls *proto_tls; +#endif + /* The global array of available protocol families */ -static struct proto_family proto_families[SAL_PROTO_FAMILIES_NUM]; +static struct sal_proto_family proto_families[SAL_PROTO_FAMILIES_NUM]; /* The global socket table */ static struct sal_socket_table socket_table; static struct rt_mutex sal_core_lock; static rt_bool_t init_ok = RT_FALSE; +#define IS_SOCKET_PROTO_TLS(sock) (((sock)->protocol == PROTOCOL_TLS) || \ + ((sock)->protocol == PROTOCOL_DTLS)) +#define SAL_SOCKOPS_PROTO_TLS_VALID(sock, name) (proto_tls && (proto_tls->ops->name) && IS_SOCKET_PROTO_TLS(sock)) + +#define SAL_SOCKOPT_PROTO_TLS_EXEC(sock, name, optval, optlen) \ +do \ +{ \ + if (SAL_SOCKOPS_PROTO_TLS_VALID(sock, name)) \ + { \ + return proto_tls->ops->name((sock)->user_data_tls, (optval), (optlen)); \ + } \ +}while(0) \ + + /** * SAL (Socket Abstraction Layer) initialize. * @@ -47,7 +70,7 @@ int sal_init(void) { int cn; - if(init_ok) + if (init_ok) { LOG_D("Socket Abstraction Layer is already initialized."); return 0; @@ -73,15 +96,32 @@ int sal_init(void) } INIT_COMPONENT_EXPORT(sal_init); +/** + * This function will register TLS protocol to the global TLS protocol. + * + * @param pt TLS protocol object + * + * @return 0: TLS protocol object register success + */ +#ifdef SAL_USING_TLS +int sal_proto_tls_register(const struct sal_proto_tls *pt) +{ + RT_ASSERT(pt); + proto_tls = (struct sal_proto_tls *) pt; + + return 0; +} +#endif + /** * This function will register protocol family to the global array of protocol families. * * @param pf protocol family object * - * @return 0 : protocol family object register success - * -1 : the global array of available protocol families is full + * @return 0: protocol family object register success + * -1: the global array of available protocol families is full */ -int sal_proto_family_register(const struct proto_family *pf) +int sal_proto_family_register(const struct sal_proto_family *pf) { rt_base_t level; int idx; @@ -92,11 +132,11 @@ int sal_proto_family_register(const struct proto_family *pf) /* check protocol family is already registered */ for(idx = 0; idx < SAL_PROTO_FAMILIES_NUM; idx++) { - if(rt_strcmp(proto_families[idx].name, pf->name) == 0) + if (proto_families[idx].family == pf->family && proto_families[idx].create) { /* enable interrupt */ rt_hw_interrupt_enable(level); - LOG_E("%s protocol family is already registered!", pf->name); + LOG_E("%s protocol family is already registered!", pf->family); return -1; } } @@ -105,22 +145,22 @@ int sal_proto_family_register(const struct proto_family *pf) for(idx = 0; idx < SAL_PROTO_FAMILIES_NUM && proto_families[idx].create; idx++); /* can't find an empty protocol family entry */ - if(idx == SAL_PROTO_FAMILIES_NUM) + if (idx == SAL_PROTO_FAMILIES_NUM) { /* enable interrupt */ rt_hw_interrupt_enable(level); return -1; } - rt_strncpy(proto_families[idx].name, pf->name, rt_strlen(pf->name)); proto_families[idx].family = pf->family; proto_families[idx].sec_family = pf->sec_family; proto_families[idx].create = pf->create; - proto_families[idx].gethostbyname = pf->gethostbyname; - proto_families[idx].gethostbyname_r = pf->gethostbyname_r; - proto_families[idx].freeaddrinfo = pf->freeaddrinfo; - proto_families[idx].getaddrinfo = pf->getaddrinfo; + proto_families[idx].ops = pf->ops; + proto_families[idx].ops->gethostbyname = pf->ops->gethostbyname; + proto_families[idx].ops->gethostbyname_r = pf->ops->gethostbyname_r; + proto_families[idx].ops->freeaddrinfo = pf->ops->freeaddrinfo; + proto_families[idx].ops->getaddrinfo = pf->ops->getaddrinfo; /* enable interrupt */ rt_hw_interrupt_enable(level); @@ -136,17 +176,17 @@ int sal_proto_family_register(const struct proto_family *pf) * @return >=0 : unregister protocol family index * -1 : unregister failed */ -int sal_proto_family_unregister(const struct proto_family *pf) +int sal_proto_family_unregister(int family) { int idx = 0; - RT_ASSERT(pf != RT_NULL); + RT_ASSERT(family > 0 && family < AF_MAX); for(idx = 0; idx < SAL_PROTO_FAMILIES_NUM; idx++) { - if(rt_strcmp(proto_families[idx].name, pf->name) == 0) + if (proto_families[idx].family == family && proto_families[idx].create) { - rt_memset(&proto_families[idx], 0x00, sizeof(struct proto_family)); + rt_memset(&proto_families[idx], 0x00, sizeof(struct sal_proto_family)); return idx; } @@ -156,21 +196,46 @@ int sal_proto_family_unregister(const struct proto_family *pf) } /** - * This function will get protocol family by name. + * This function will judge whether protocol family is registered * - * @param name protocol family name + * @param family protocol family number + * + * @return 1: protocol family is registered + * 0: protocol family is not registered + */ +rt_bool_t sal_proto_family_is_registered(int family) +{ + int idx = 0; + + RT_ASSERT(family > 0 && family < AF_MAX); + + for (idx = 0; idx < SAL_PROTO_FAMILIES_NUM; idx++) + { + if (proto_families[idx].family == family && proto_families[idx].create) + { + return RT_TRUE; + } + } + + return RT_FALSE; +} + +/** + * This function will get protocol family object by family number. + * + * @param family protocol family number * * @return protocol family object */ -struct proto_family *sal_proto_family_find(const char *name) +struct sal_proto_family *sal_proto_family_find(int family) { int idx = 0; - RT_ASSERT(name != RT_NULL); + RT_ASSERT(family > 0 && family < AF_MAX); for (idx = 0; idx < SAL_PROTO_FAMILIES_NUM; idx++) { - if (rt_strcmp(proto_families[idx].name, name) == 0) + if (proto_families[idx].family == family && proto_families[idx].create) { return &proto_families[idx]; } @@ -238,7 +303,7 @@ static void sal_unlock(void) * * @return protocol family structure address */ -static struct proto_family *get_proto_family(int family) +static struct sal_proto_family *get_proto_family(int family) { int idx; @@ -278,7 +343,7 @@ static struct proto_family *get_proto_family(int family) static int socket_init(int family, int type, int protocol, struct sal_socket **res) { struct sal_socket *sock; - struct proto_family *pf; + struct sal_proto_family *pf; if (family < 0 || family > AF_MAX) { @@ -383,6 +448,11 @@ static int socket_new(void) sock = st->sockets[idx]; sock->socket = idx + SAL_SOCKET_OFFSET; sock->magic = SAL_SOCKET_MAGIC; + sock->ops = RT_NULL; + sock->user_data = RT_NULL; +#ifdef SAL_USING_TLS + sock->user_data_tls = RT_NULL; +#endif __result: sal_unlock(); @@ -474,6 +544,15 @@ int sal_shutdown(int socket, int how) if (sock->ops->shutdown((int) sock->user_data, how) == 0) { +#ifdef SAL_USING_TLS + if (SAL_SOCKOPS_PROTO_TLS_VALID(sock, closesocket)) + { + if (proto_tls->ops->closesocket(sock->user_data_tls) < 0) + { + return -1; + } + } +#endif rt_free(sock); socket_table.sockets[socket] = RT_NULL; return 0; @@ -551,12 +630,46 @@ int sal_setsockopt(int socket, int level, int optname, const void *optval, sockl return -RT_ENOSYS; } +#ifdef SAL_USING_TLS + if (level == SOL_TLS) + { + switch (optname) + { + case TLS_CRET_LIST: + SAL_SOCKOPT_PROTO_TLS_EXEC(sock, set_cret_list, optval, optlen); + break; + + case TLS_CIPHERSUITE_LIST: + SAL_SOCKOPT_PROTO_TLS_EXEC(sock, set_ciphersurite, optval, optlen); + break; + + case TLS_PEER_VERIFY: + SAL_SOCKOPT_PROTO_TLS_EXEC(sock, set_peer_verify, optval, optlen); + break; + + case TLS_DTLS_ROLE: + SAL_SOCKOPT_PROTO_TLS_EXEC(sock, set_dtls_role, optval, optlen); + break; + + default: + return -1; + } + + return 0; + } + else + { + return sock->ops->setsockopt((int) sock->user_data, level, optname, optval, optlen); + } +#else return sock->ops->setsockopt((int) sock->user_data, level, optname, optval, optlen); +#endif /* SAL_USING_TLS */ } int sal_connect(int socket, const struct sockaddr *name, socklen_t namelen) { struct sal_socket *sock; + int ret; sock = sal_get_socket(socket); if (!sock) @@ -569,7 +682,20 @@ int sal_connect(int socket, const struct sockaddr *name, socklen_t namelen) return -RT_ENOSYS; } - return sock->ops->connect((int) sock->user_data, name, namelen); + ret = sock->ops->connect((int) sock->user_data, name, namelen); +#ifdef SAL_USING_TLS + if (ret >= 0 && SAL_SOCKOPS_PROTO_TLS_VALID(sock, connect)) + { + if (proto_tls->ops->connect(sock->user_data_tls) < 0) + { + return -1; + } + + return ret; + } +#endif + + return ret; } int sal_listen(int socket, int backlog) @@ -606,7 +732,24 @@ int sal_recvfrom(int socket, void *mem, size_t len, int flags, return -RT_ENOSYS; } +#ifdef SAL_USING_TLS + if (SAL_SOCKOPS_PROTO_TLS_VALID(sock, recv)) + { + int ret; + + if ((ret = proto_tls->ops->recv(sock->user_data_tls, mem, len)) < 0) + { + return -1; + } + return ret; + } + else + { + return sock->ops->recvfrom((int) sock->user_data, mem, len, flags, from, fromlen); + } +#else return sock->ops->recvfrom((int) sock->user_data, mem, len, flags, from, fromlen); +#endif } int sal_sendto(int socket, const void *dataptr, size_t size, int flags, @@ -625,7 +768,24 @@ int sal_sendto(int socket, const void *dataptr, size_t size, int flags, return -RT_ENOSYS; } +#ifdef SAL_USING_TLS + if (SAL_SOCKOPS_PROTO_TLS_VALID(sock, send)) + { + int ret; + + if ((ret = proto_tls->ops->send(sock->user_data_tls, dataptr, size)) < 0) + { + return -1; + } + return ret; + } + else + { + return sock->ops->sendto((int) sock->user_data, dataptr, size, flags, to, tolen); + } +#else return sock->ops->sendto((int) sock->user_data, dataptr, size, flags, to, tolen); +#endif } int sal_socket(int domain, int type, int protocol) @@ -657,8 +817,17 @@ int sal_socket(int domain, int type, int protocol) proto_socket = sock->ops->socket(domain, type, protocol); if (proto_socket >= 0) { +#ifdef SAL_USING_TLS + if (SAL_SOCKOPS_PROTO_TLS_VALID(sock, socket)) + { + sock->user_data_tls = proto_tls->ops->socket(proto_socket); + if (sock->user_data_tls == RT_NULL) + { + return -1; + } + } +#endif sock->user_data = (void *) proto_socket; - return sock->socket; } @@ -682,6 +851,15 @@ int sal_closesocket(int socket) if (sock->ops->closesocket((int) sock->user_data) == 0) { +#ifdef SAL_USING_TLS + if (SAL_SOCKOPS_PROTO_TLS_VALID(sock, closesocket)) + { + if (proto_tls->ops->closesocket(sock->user_data_tls) < 0) + { + return -1; + } + } +#endif rt_free(sock); socket_table.sockets[socket] = RT_NULL; return 0; @@ -736,9 +914,9 @@ struct hostent *sal_gethostbyname(const char *name) for (i = 0; i < SAL_PROTO_FAMILIES_NUM; ++i) { - if (proto_families[i].gethostbyname) + if (proto_families[i].ops && proto_families[i].ops->gethostbyname) { - hst = proto_families[i].gethostbyname(name); + hst = proto_families[i].ops->gethostbyname(name); if (hst != RT_NULL) { return hst; @@ -756,9 +934,9 @@ int sal_gethostbyname_r(const char *name, struct hostent *ret, char *buf, for (i = 0; i < SAL_PROTO_FAMILIES_NUM; ++i) { - if (proto_families[i].gethostbyname_r) + if (proto_families[i].ops && proto_families[i].ops->gethostbyname_r) { - res = proto_families[i].gethostbyname_r(name, ret, buf, buflen, result, h_errnop); + res = proto_families[i].ops->gethostbyname_r(name, ret, buf, buflen, result, h_errnop); if (res == 0) { return res; @@ -769,20 +947,6 @@ int sal_gethostbyname_r(const char *name, struct hostent *ret, char *buf, return -1; } -void sal_freeaddrinfo(struct addrinfo *ai) -{ - int i; - - for (i = 0; i < SAL_PROTO_FAMILIES_NUM; ++i) - { - if (proto_families[i].freeaddrinfo) - { - proto_families[i].freeaddrinfo(ai); - return; - } - } -} - int sal_getaddrinfo(const char *nodename, const char *servname, const struct addrinfo *hints, @@ -792,9 +956,9 @@ int sal_getaddrinfo(const char *nodename, for (i = 0; i < SAL_PROTO_FAMILIES_NUM; ++i) { - if (proto_families[i].getaddrinfo) + if (proto_families[i].ops && proto_families[i].ops->getaddrinfo) { - ret = proto_families[i].getaddrinfo(nodename, servname, hints, res); + ret = proto_families[i].ops->getaddrinfo(nodename, servname, hints, res); if (ret == 0) { return ret; @@ -804,3 +968,17 @@ int sal_getaddrinfo(const char *nodename, return -1; } + +void sal_freeaddrinfo(struct addrinfo *ai) +{ + int i; + + for (i = 0; i < SAL_PROTO_FAMILIES_NUM; ++i) + { + if (proto_families[i].ops && proto_families[i].ops->freeaddrinfo) + { + proto_families[i].ops->freeaddrinfo(ai); + return; + } + } +} diff --git a/components/utilities/Kconfig b/components/utilities/Kconfig index e830d94578bb18fd361c0dc99bac96d96b8585b5..8e43cfa0a0ff96ead711429f7c122e2457bd4d46 100644 --- a/components/utilities/Kconfig +++ b/components/utilities/Kconfig @@ -230,4 +230,8 @@ config RT_USING_ULOG sfotware module version number endif +config RT_USING_UTEST + bool "Enable utest (RT-Thread test framework)" + default n + endmenu diff --git a/components/utilities/ulog/ulog.h b/components/utilities/ulog/ulog.h index 792c098568c0cb4aafcb82288dac60fde6395359..c78d72eda5e012f30599943e5bcc860f235255ec 100644 --- a/components/utilities/ulog/ulog.h +++ b/components/utilities/ulog/ulog.h @@ -45,6 +45,7 @@ void ulog_deinit(void); #define LOG_I(...) ulog_i(LOG_TAG, __VA_ARGS__) #define LOG_D(...) ulog_d(LOG_TAG, __VA_ARGS__) #define LOG_RAW(...) ulog_raw(__VA_ARGS__) +#define LOG_HEX(name, width, buf, size) ulog_hex(name, width, buf, size) /* * backend register and unregister diff --git a/components/utilities/ulog/ulog_def.h b/components/utilities/ulog/ulog_def.h index 8df3dd2087a3a117876f979618cdfe9106b0ed62..e7c033f71c9bd28f031fa2fdf49339d71a0b1892 100644 --- a/components/utilities/ulog/ulog_def.h +++ b/components/utilities/ulog/ulog_def.h @@ -94,6 +94,12 @@ extern "C" { #define ulog_e(TAG, ...) #endif /* (LOG_LVL >= LOG_LVL_ERROR) && (ULOG_OUTPUT_LVL >= LOG_LVL_ERROR) */ +#if (LOG_LVL >= LOG_LVL_DBG) && (ULOG_OUTPUT_LVL >= LOG_LVL_DBG) + #define ulog_hex(TAG, width, buf, size) ulog_hexdump(TAG, width, buf, size) +#else + #define ulog_hex(TAG, width, buf, size) +#endif /* (LOG_LVL >= LOG_LVL_DBG) && (ULOG_OUTPUT_LVL >= LOG_LVL_DBG) */ + /* assert for developer. */ #ifdef ULOG_ASSERT_ENABLE #define ULOG_ASSERT(EXPR) \ @@ -132,6 +138,7 @@ extern "C" { #define log_d LOG_D #define log_v LOG_D #define log_raw LOG_RAW +#define log_hex LOG_HEX #define ELOG_LVL_ASSERT LOG_LVL_ASSERT #define ELOG_LVL_ERROR LOG_LVL_ERROR #define ELOG_LVL_WARN LOG_LVL_WARNING diff --git a/components/utilities/utest/SConscript b/components/utilities/utest/SConscript new file mode 100644 index 0000000000000000000000000000000000000000..dc77bc2591a0269e33ac90114eb8e04bfd994e87 --- /dev/null +++ b/components/utilities/utest/SConscript @@ -0,0 +1,8 @@ +from building import * + +cwd = GetCurrentDir() +src = Glob('*.c') +CPPPATH = [cwd] +group = DefineGroup('utest', src, depend = ['RT_USING_UTEST'], CPPPATH = CPPPATH) + +Return('group') diff --git a/components/utilities/utest/utest.c b/components/utilities/utest/utest.c new file mode 100644 index 0000000000000000000000000000000000000000..0f5a206d3c1027206feba8f99c93d616d2acaef8 --- /dev/null +++ b/components/utilities/utest/utest.c @@ -0,0 +1,238 @@ +/* + * Copyright (c) 2006-2018, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2018-11-19 MurphyZhao the first version + */ + +#include "utest.h" +#include +#include + +#undef DBG_SECTION_NAME +#undef DBG_LEVEL +#undef DBG_COLOR +#undef DBG_ENABLE + +#define DBG_ENABLE +#define DBG_SECTION_NAME "utest" +#ifdef UTEST_DEBUG +#define DBG_LEVEL DBG_LOG +#else +#define DBG_LEVEL DBG_INFO +#endif +#define DBG_COLOR +#include + +#if RT_CONSOLEBUF_SIZE < 256 +#error "RT_CONSOLEBUF_SIZE is less than 256!" +#endif + +static utest_tc_export_t tc_table = RT_NULL; +static rt_size_t tc_num; +static struct utest local_utest = {UTEST_PASSED, 0, 0}; + +#if defined(__ICCARM__) || defined(__ICCRX__) /* for IAR compiler */ +#pragma section="UtestTcTab" +#endif + +int utest_init(void) +{ + /* initialize the utest commands table.*/ +#if defined(__CC_ARM) /* ARM C Compiler */ + extern const int UtestTcTab$$Base; + extern const int UtestTcTab$$Limit; + tc_table = (utest_tc_export_t)&UtestTcTab$$Base; + tc_num = (utest_tc_export_t)&UtestTcTab$$Limit - tc_table; +#elif defined (__ICCARM__) || defined(__ICCRX__) /* for IAR Compiler */ + tc_table = (utest_tc_export_t)__section_begin("UtestTcTab"); + tc_num = (utest_tc_export_t)__section_end("UtestTcTab") - tc_table; +#elif defined (__GNUC__) /* for GCC Compiler */ + extern const int __rt_utest_tc_tab_start; + extern const int __rt_utest_tc_tab_end; + tc_table = (utest_tc_export_t)&__rt_utest_tc_tab_start; + tc_num = (utest_tc_export_t) &__rt_utest_tc_tab_end - tc_table; +#endif /* defined(__CC_ARM) */ + + LOG_I("utest is initialize success."); + LOG_I("total utest testcase num: (%d)", tc_num); + return tc_num; +} +INIT_COMPONENT_EXPORT(utest_init); + +static void utest_tc_list(void) +{ + rt_size_t i = 0; + + LOG_I("Commands list : "); + + for (i = 0; i < tc_num; i++) + { + LOG_I("[testcase name]:%s; [run timeout]:%d", tc_table[i].name, tc_table[i].run_timeout); + } +} +MSH_CMD_EXPORT_ALIAS(utest_tc_list, utest_list, output all utest testcase); + +static const char *file_basename(const char *file) +{ + char *end_ptr = RT_NULL; + char *rst = RT_NULL; + + if (!((end_ptr = strrchr(file, '\\')) != RT_NULL || \ + (end_ptr = strrchr(file, '/')) != RT_NULL) || \ + (rt_strlen(file) < 2)) + { + rst = (char *)file; + } + else + { + rst = (char *)(end_ptr + 1); + } + return (const char *)rst; +} + +static void utest_run(const char *utest_name) +{ + rt_size_t i = 0; + + LOG_I("[==========] [ utest ] started"); + while(i < tc_num) + { + if (utest_name && rt_strcmp(utest_name, tc_table[i].name)) + { + i++; + continue; + } + + LOG_I("[----------] [ testcase ] (%s) started", tc_table[i].name); + if (tc_table[i].init != RT_NULL) + { + if (tc_table[i].init() != RT_EOK) + { + LOG_I("[ FAILED ] [ result ] testcase (%s)", tc_table[i].name); + goto __tc_continue; + } + } + + if (tc_table[i].tc != RT_NULL) + { + tc_table[i].tc(); + if (local_utest.failed_num == 0) + { + LOG_I("[ PASSED ] [ result ] testcase (%s)", tc_table[i].name); + } + else + { + LOG_I("[ FAILED ] [ result ] testcase (%s)", tc_table[i].name); + } + } + else + { + LOG_I("[ FAILED ] [ result ] testcase (%s)", tc_table[i].name); + } + + if (tc_table[i].cleanup != RT_NULL) + { + if (tc_table[i].cleanup() != RT_EOK) + { + LOG_I("[ FAILED ] [ result ] testcase (%s)", tc_table[i].name); + goto __tc_continue; + } + } + +__tc_continue: + LOG_I("[----------] [ testcase ] (%s) finished", tc_table[i].name); + + i++; + } + LOG_I("[==========] [ utest ] finished"); +} + +static void utest_testcase_run(int argc, char** argv) +{ + char utest_name[UTEST_NAME_MAX_LEN]; + + if (argc == 1) + { + utest_run(RT_NULL); + } + else if (argc == 2) + { + rt_memset(utest_name, 0x0, sizeof(utest_name)); + rt_strncpy(utest_name, argv[1], sizeof(utest_name) -1); + utest_run(utest_name); + } + else + { + LOG_E("[ error ] at (%s:%d), in param error.", __func__, __LINE__); + } +} +MSH_CMD_EXPORT_ALIAS(utest_testcase_run, utest_run, utest_run [testcase name]); + +utest_t utest_handle_get(void) +{ + return (utest_t)&local_utest; +} + +void utest_unit_run(test_unit_func func, const char *unit_func_name) +{ + // LOG_I("[==========] utest unit name: (%s)", unit_func_name); + local_utest.error = UTEST_PASSED; + local_utest.passed_num = 0; + local_utest.failed_num = 0; + + if (func != RT_NULL) + { + func(); + } +} + +void utest_assert(int value, const char *file, int line, const char *func, const char *msg) +{ + if (!(value)) + { + local_utest.error = UTEST_FAILED; + local_utest.failed_num ++; + LOG_E("[ ASSERT ] [ unit ] at (%s); func: (%s:%d); msg: (%s)", file_basename(file), func, line, msg); + } + else + { + LOG_D("[ OK ] [ unit ] (%s:%d) is passed", func, line); + local_utest.error = UTEST_PASSED; + local_utest.passed_num ++; + } +} + +void utest_assert_string(const char *a, const char *b, rt_bool_t equal, const char *file, int line, const char *func, const char *msg) +{ + if (a == RT_NULL || b == RT_NULL) + { + utest_assert(0, file, line, func, msg); + } + + if (equal) + { + if (rt_strcmp(a, b) == 0) + { + utest_assert(1, file, line, func, msg); + } + else + { + utest_assert(0, file, line, func, msg); + } + } + else + { + if (rt_strcmp(a, b) == 0) + { + utest_assert(0, file, line, func, msg); + } + else + { + utest_assert(1, file, line, func, msg); + } + } +} diff --git a/components/utilities/utest/utest.h b/components/utilities/utest/utest.h new file mode 100644 index 0000000000000000000000000000000000000000..5a7e8af7214bb56c2211c8124040c6cee1794051 --- /dev/null +++ b/components/utilities/utest/utest.h @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2006-2018, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2018-11-19 MurphyZhao the first version + */ + +#ifndef __UTEST_H__ +#define __UTEST_H__ + +#include +#include "utest_log.h" + +/** + * utest_error + * + * @brief Test result. + * + * @member UTEST_PASSED Test success. + * @member UTEST_FAILED Test failed. + * @member UTEST_PASSED Test skipped. + * +*/ +enum utest_error +{ + UTEST_PASSED = 0, + UTEST_FAILED = 1, + UTEST_SKIPPED = 2 +}; +typedef enum utest_error utest_err_e; + +/** + * utest + * + * @brief utest data structure. + * + * @member error Error number from enum `utest_error`. + * @member passed_num Total number of tests passed. + * @member failed_num Total number of tests failed. + * +*/ +struct utest +{ + utest_err_e error; + uint32_t passed_num; + uint32_t failed_num; +}; +typedef struct utest *utest_t; + +/** + * utest_tc_export + * + * @brief utest testcase data structure. + * Will export the data to `UtestTcTab` section in flash. + * + * @member name Testcase name. + * @member run_timeout Testcase maximum test time. + * @member init Necessary initialization before executing the test case function. + * @member tc Total number of tests failed. + * @member cleanup Total number of tests failed. + * +*/ +struct utest_tc_export { + const char *name; + uint32_t run_timeout; + rt_err_t (*init)(void); + void (*tc)(void); + rt_err_t (*cleanup)(void); +}; +typedef struct utest_tc_export *utest_tc_export_t; + +/** + * test_unit_func + * + * @brief Unit test handler function pointer. + * +*/ +typedef void (*test_unit_func)(void); + +/** + * utest_unit_run + * + * @brief Unit test function executor. + * No need for the user to call this function directly + * + * @param func Unit test function. + * @param unit_func_name Unit test function name. + * + * @return void + * +*/ +void utest_unit_run(test_unit_func func, const char *unit_func_name); + +/** + * utest_handle_get + * + * @brief Get the utest data structure handle. + * No need for the user to call this function directly + * + * @param void + * + * @return utest_t type. (struct utest *) + * +*/ +utest_t utest_handle_get(void); + +/** + * UTEST_NAME_MAX_LEN + * + * @brief Testcase name maximum length. + * +*/ +#define UTEST_NAME_MAX_LEN (128u) + +/** + * UTEST_TC_EXPORT + * + * @brief Export testcase function to `UtestTcTab` section in flash. + * Used in application layer. + * + * @param testcase The testcase function. + * @param name The testcase name. + * @param init The initialization function of the test case. + * @param cleanup The cleanup function of the test case. + * @param timeout Testcase maximum test time. + * + * @return None + * +*/ +#define UTEST_TC_EXPORT(testcase, name, init, cleanup, timeout) \ + RT_USED static const struct utest_tc_export _utest_testcase \ + SECTION("UtestTcTab") = \ + { \ + name, \ + timeout, \ + init, \ + testcase, \ + cleanup \ + } + +/** + * UTEST_UNIT_RUN + * + * @brief Unit test function executor. + * Used in `testcase` function in application. + * + * @param test_unit_func Unit test function + * + * @return None + * +*/ +#define UTEST_UNIT_RUN(test_unit_func) \ + utest_unit_run(test_unit_func, #test_unit_func); \ + if(utest_handle_get()->failed_num != 0) return; + +#endif /* __UTEST_H__ */ diff --git a/components/utilities/utest/utest_assert.h b/components/utilities/utest/utest_assert.h new file mode 100644 index 0000000000000000000000000000000000000000..997e8ae7f32cb8563684d21ab2b0b4eb26493330 --- /dev/null +++ b/components/utilities/utest/utest_assert.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2006-2018, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2018-11-19 MurphyZhao the first version + */ + +#ifndef __UTEST_ASSERT_H__ +#define __UTEST_ASSERT_H__ + +#include "utest.h" +#include + +/* No need for the user to use this function directly */ +void utest_assert(int value, const char *file, int line, const char *func, const char *msg); + +/* No need for the user to use this function directly */ +void utest_assert_string(const char *a, const char *b, rt_bool_t equal, const char *file, int line, const char *func, const char *msg); + +/* No need for the user to use this macro directly */ +#define __utest_assert(value, msg) utest_assert(value, __FILE__, __LINE__, __func__, msg) + +/** + * uassert_x macros + * + * @brief Get the utest data structure handle. + * No need for the user to call this function directly. + * + * @macro uassert_true if @value is true, not assert, means passing. + * @macro uassert_false if @value is false, not assert, means passing. + * @macro uassert_null if @value is null, not assert, means passing. + * @macro uassert_not_null if @value is not null, not assert, means passing. + * @macro uassert_int_equal if @a equal to @b, not assert, means passing. Integer type test. + * @macro uassert_int_not_equal if @a not equal to @b, not assert, means passing. Integer type test. + * @macro uassert_str_equal if @a equal to @b, not assert, means passing. String type test. + * @macro uassert_str_not_equal if @a not equal to @b, not assert, means passing. String type test. + * @macro uassert_in_range if @value is in range of min and max, not assert, means passing. + * @macro uassert_not_in_range if @value is not in range of min and max, not assert, means passing. + * +*/ +#define uassert_true(value) __utest_assert(value, "(" #value ") is false") +#define uassert_false(value) __utest_assert(!(value), "(" #value ") is true") +#define uassert_null(value) __utest_assert((const char *)(value) == NULL, "(" #value ") is not null") +#define uassert_not_null(value) __utest_assert((const char *)(value) != NULL, "(" #value ") is null") + +#define uassert_int_equal(a, b) __utest_assert((a) == (b), "(" #a ") not equal to (" #b ")") +#define uassert_int_not_equal(a, b) __utest_assert((a) != (b), "(" #a ") equal to (" #b ")") + +#define uassert_str_equal(a, b) utest_assert_string((const char*)(a), (const char*)(b), RT_TRUE, __FILE__, __LINE__, __func__, "string not equal") +#define uassert_str_not_equal(a, b) utest_assert_string((const char*)(a), (const char*)(b), RT_FALSE, __FILE__, __LINE__, __func__, "string equal") + +#define uassert_in_range(value, min, max) __utest_assert(((value >= min) && (value <= max)), "(" #value ") not in range("#min","#max")") +#define uassert_not_in_range(value, min, max) __utest_assert(!((value >= min) && (value <= max)), "(" #value ") in range("#min","#max")") + +#endif /* __UTEST_ASSERT_H__ */ diff --git a/components/utilities/utest/utest_log.h b/components/utilities/utest/utest_log.h new file mode 100644 index 0000000000000000000000000000000000000000..c954046b7627bfa33c20c0ec8f0fae3d47671c95 --- /dev/null +++ b/components/utilities/utest/utest_log.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2006-2018, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2018-11-19 MurphyZhao the first version + */ + +#ifndef __UTEST_LOG_H__ +#define __UTEST_LOG_H__ + +#define UTEST_DEBUG + +#undef DBG_SECTION_NAME +#undef DBG_LEVEL +#undef DBG_COLOR +#undef DBG_ENABLE + +#define DBG_ENABLE +#define DBG_SECTION_NAME "testcase" +#ifdef UTEST_DEBUG +#define DBG_LEVEL DBG_LOG +#else +#define DBG_LEVEL DBG_INFO +#endif +#define DBG_COLOR +#include + +#endif /* __UTEST_LOG_H__ */