未验证 提交 b2f28254 编写于 作者: W WCX 提交者: GitHub

[bsp][bouffalo] add hwtimer & flash driver support (#7203)

* add hwtimer & flash driver support
上级 aeed2eeb
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2023-04-08 wcx1024979076 first version
*/
/*
* 程序清单:这是一个 dfs 虚拟文件系统挂载文件系统使用例程
* 例程导出了 mnt_init 命令到应用初始化中
* 程序功能:挂载 elm 文件系统到片上flash filesystem 分区中
* 使用前参考文章 https://blog.csdn.net/h451884098/article/details/118544347 和 https://blog.csdn.net/u013213069/article/details/117384971 开启以下配置:
* 1、修改 menuconfig 打开RT_USING_DFS 和 elm-chan 文件系统并修改扇区 sector 大小为 4096
* 2、修改 components/dfs/dfs_v1/include/dfs.h 和 components/dfs/dfs_v2/include/dfs.h 中 SECTOR_SIZE 改为 4096
* 3、修改芯片外设配置打开 BSP_USING_ON_CHIP_FLASH
* 4、修改 menuconfig 打开 RT_USING_FAL 配置
*/
#include <rtthread.h>
#include <rtdevice.h>
#ifdef RT_USING_DFS
#ifdef RT_USING_FAL
#ifdef BSP_USING_ON_CHIP_FLASH
#include "dfs_file.h"
#include "fal.h"
int mnt_init(void)
{
struct rt_device *rootfs = RT_NULL;
/* 使用 filesystem 分区创建块设备,块设备名称为 filesystem */
rootfs = fal_blk_device_create("filesystem");
if(rootfs == RT_NULL)
return -RT_ERROR;
/* 将 elm fat 文件系统挂载 filesystem 分区 */
if (dfs_mount("filesystem", "/", "elm", 0, 0) == 0)
{
rt_kprintf("file system initialization done!\n");
}
else
{
if(dfs_mkfs("elm", "filesystem") == 0)
{
if (dfs_mount("filesystem", "/", "elm", 0, 0) == 0)
{
rt_kprintf("file system initialization done!\n");
}
else
{
rt_kprintf("file system initialization failed!\n");
}
}
}
return RT_EOK;
}
INIT_APP_EXPORT(mnt_init);
#endif /* RT_USING_DFS */
#endif /* RT_USING_FAL */
#endif /* BSP_USING_ON_CHIP_FLASH */
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2023-04-01 wcx1024979076 first version.
*/
/*
* 程序清单:这是一个 hwtimer 设备使用例程
* 例程导出了 hwtimer_sample 命令到控制终端
* 命令调用格式:hwtimer_sample
* 程序功能:硬件定时器超时回调函数周期性的打印当前tick值,2次tick值之差换算为时间等同于定时时间值。
*/
#include <rtthread.h>
#include <rtdevice.h>
#ifdef RT_USING_HWTIMER
#define HWTIMER_DEV_NAME "timer0" /* 定时器名称 */
/* 定时器超时回调函数 */
static rt_err_t timeout_cb(rt_device_t dev, rt_size_t size)
{
rt_kprintf("this is hwtimer timeout callback fucntion!\n");
rt_kprintf("tick is :%d !\n", rt_tick_get());
return 0;
}
static int hwtimer_sample(int argc, char *argv[])
{
rt_err_t ret = RT_EOK;
rt_hwtimerval_t timeout_s; /* 定时器超时值 */
rt_device_t hw_dev = RT_NULL; /* 定时器设备句柄 */
rt_hwtimer_mode_t mode; /* 定时器模式 */
rt_uint32_t freq = 10000; /* 计数频率 */
/* 查找定时器设备 */
hw_dev = rt_device_find(HWTIMER_DEV_NAME);
if (hw_dev == RT_NULL)
{
rt_kprintf("hwtimer sample run failed! can't find %s device!\n", HWTIMER_DEV_NAME);
return -RT_ERROR;
}
/* 以读写方式打开设备 */
ret = rt_device_open(hw_dev, RT_DEVICE_OFLAG_RDWR);
if (ret != RT_EOK)
{
rt_kprintf("open %s device failed!\n", HWTIMER_DEV_NAME);
return ret;
}
/* 设置超时回调函数 */
rt_device_set_rx_indicate(hw_dev, timeout_cb);
/* 设置计数频率(若未设置该项,默认为1Mhz 或 支持的最小计数频率) */
rt_device_control(hw_dev, HWTIMER_CTRL_FREQ_SET, &freq);
/* 设置模式为周期性定时器(若未设置,默认是HWTIMER_MODE_ONESHOT)*/
mode = HWTIMER_MODE_PERIOD;
ret = rt_device_control(hw_dev, HWTIMER_CTRL_MODE_SET, &mode);
if (ret != RT_EOK)
{
rt_kprintf("set mode failed! ret is :%d\n", ret);
return ret;
}
/* 设置定时器超时值为2s并启动定时器 */
timeout_s.sec = 2; /* 秒 */
timeout_s.usec = 0; /* 微秒 */
if (rt_device_write(hw_dev, 0, &timeout_s, sizeof(timeout_s)) != sizeof(timeout_s))
{
rt_kprintf("set timeout value failed\n");
return -RT_ERROR;
}
/* 延时1500ms */
rt_thread_mdelay(1500);
/* 读取定时器当前值 */
rt_device_read(hw_dev, 0, &timeout_s, sizeof(timeout_s));
rt_kprintf("Read: Sec = %d, Usec = %d\n", timeout_s.sec, timeout_s.usec);
return ret;
}
/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(hwtimer_sample, hwtimer sample);
#endif /* RT_USING_HWTIMER */
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2023-04-08 wcx1024979076 the first version
*/
#ifndef _FAL_CFG_H_
#define _FAL_CFG_H_
#include <rtconfig.h>
#include <board.h>
/* ===================== Flash device Configuration ========================= */
extern const struct fal_flash_dev _onchip_flash;
/* flash device table */
#define FAL_FLASH_DEV_TABLE \
{ \
&_onchip_flash, \
}
/* ====================== Partition Configuration ========================== */
#ifdef FAL_PART_HAS_TABLE_CFG
/* partition table */
#define FAL_PART_TABLE \
{ \
{FAL_PART_MAGIC_WORD, "bl", "bflb_onchip", 0, 8 * 1024 * 1024, 0}, \
{FAL_PART_MAGIC_WORD, "filesystem", "bflb_onchip", 8 * 1024 * 1024, 8 * 1024 * 1024, 0}, \
}
#endif /* FAL_PART_HAS_TABLE_CFG */
#endif /* _FAL_CFG_H_ */
......@@ -158,5 +158,22 @@ menu "General Drivers Configuration"
default n
endif
menuconfig BSP_USING_HWTIMER
bool "Enable HWTIMER"
default n
select RT_USING_HWTIMER
if BSP_USING_HWTIMER
config BSP_USING_TIMER0
bool "Enable TIMER0"
default n
config BSP_USING_TIMER1
bool "Enable TIMER1"
default n
endif
config BSP_USING_ON_CHIP_FLASH
bool "Enable on-chip FLASH"
default n
endmenu
......@@ -24,6 +24,12 @@ if GetDepend('RT_USING_PWM'):
if GetDepend('RT_USING_WDT'):
src += ['drv_wdt.c']
if GetDepend('BSP_USING_HWTIMER'):
src += ['drv_hwtimer.c']
if GetDepend('BSP_USING_ON_CHIP_FLASH'):
src += ['drv_flash.c']
group = DefineGroup('rt_drivers', src, depend = [''], CPPPATH = CPPPATH)
objs = [group]
......
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2023-04-08 wcx1024979076 first version
*/
#include <rtthread.h>
#include <rtdevice.h>
#ifdef BSP_USING_ON_CHIP_FLASH
#include "drv_flash.h"
#ifdef RT_USING_FAL
#include "fal.h"
#endif /* RT_USING_FAL */
#define DBG_LEVEL DBG_LOG
#define LOG_TAG "DRV.FLASH"
#include <rtdbg.h>
#define BFLB_FLASH_START_ADRESS 0x58000000
#define BFLB_FLASH_SIZE 16 * 1024 * 1024
#define BFLB_FLASH_PAGE_SIZE 4 * 1024
#define BFLB_FLASH_END_ADDRESS 0x59000000
int _flash_read(rt_uint32_t addr, rt_uint8_t *buf, size_t size)
{
rt_err_t result = RT_EOK;
if ((addr + size) > BFLB_FLASH_END_ADDRESS)
{
LOG_E("read outrange flash size! addr is (0x%p)", (void *)(addr + size));
return -RT_EINVAL;
}
result = bflb_flash_read(addr - BFLB_FLASH_START_ADRESS, buf, size);
if(result != RT_EOK)
{
LOG_E("READ ERROR result = %d, addr = %d, addr1 = %d, len = %d", result, addr, addr - BFLB_FLASH_START_ADRESS, size);
return -RT_ERROR;
}
else
{
return size;
}
}
int _flash_write(rt_uint32_t addr, const rt_uint8_t *buf, size_t size)
{
rt_err_t result = RT_EOK;
rt_uint32_t end_addr = addr + size;
if (addr % 4 != 0)
{
LOG_E("write addr must be 4-byte alignment");
return -RT_EINVAL;
}
if ((end_addr) > BFLB_FLASH_END_ADDRESS)
{
LOG_E("write outrange flash size! addr is (0x%p)", (void *)(addr + size));
return -RT_EINVAL;
}
result = bflb_flash_write(addr - BFLB_FLASH_START_ADRESS, buf, size);
if(result != RT_EOK)
{
LOG_E("WRITE ERROR result = %d, addr = %d, addr1 = %d, len = %d", result, addr, addr - BFLB_FLASH_START_ADRESS, size);
return -RT_ERROR;
}
else
{
return size;
}
}
int _flash_erase(rt_uint32_t addr, size_t size)
{
rt_err_t result = RT_EOK;
rt_uint32_t end_addr = addr + size;
rt_uint32_t page_addr = 0;
if ((end_addr) > BFLB_FLASH_END_ADDRESS)
{
LOG_E("erase outrange flash size! addr is (0x%p)", (void *)(addr + size));
return -RT_EINVAL;
}
result = bflb_flash_erase(addr - BFLB_FLASH_START_ADRESS, size);
if (result != RT_EOK)
{
LOG_E("ERASE ERROR result = %d, addr = %d, addr1 = %d, size = %d", result, addr, addr - BFLB_FLASH_START_ADRESS, size);
return -RT_ERROR;
}
else
{
return size;
}
}
#ifdef RT_USING_FAL
static int fal_flash_read(long offset, rt_uint8_t *buf, size_t size);
static int fal_flash_write(long offset, const rt_uint8_t *buf, size_t size);
static int fal_flash_erase(long offset, size_t size);
const struct fal_flash_dev _onchip_flash =
{
"bflb_onchip",
BFLB_FLASH_START_ADRESS,
BFLB_FLASH_SIZE,
BFLB_FLASH_PAGE_SIZE,
{
NULL,
fal_flash_read,
fal_flash_write,
fal_flash_erase
}
};
static int fal_flash_read(long offset, rt_uint8_t *buf, size_t size)
{
return _flash_read(_onchip_flash.addr + offset, buf, size);
}
static int fal_flash_write(long offset, const rt_uint8_t *buf, size_t size)
{
return _flash_write(_onchip_flash.addr + offset, buf, size);
}
static int fal_flash_erase(long offset, size_t size)
{
return _flash_erase(_onchip_flash.addr + offset, size);
}
INIT_DEVICE_EXPORT(fal_init);
#endif /* RT_USING_FAL */
#endif /* BSP_USING_ON_CHIP_FLASH */
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2023-04-08 wcx1024979076 first version
*/
#ifndef __DRV_FLASH_H__
#define __DRV_FLASH_H__
#include "bflb_flash.h"
#include "board.h"
int _flash_read(rt_uint32_t addr, rt_uint8_t *buf, size_t size);
int _flash_write(rt_uint32_t addr, const rt_uint8_t *buf, size_t size);
int _flash_erase(rt_uint32_t addr, size_t size);
#endif /* __DRV_FLASH_H__ */
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2023-04-01 wcx1024979076 first version
*/
#include <rtthread.h>
#include <rtdevice.h>
#define DBG_LEVEL DBG_LOG
#include <rtdbg.h>
#define LOG_TAG "DRV.HWTIMER"
#ifdef RT_USING_HWTIMER
#include "drv_hwtimer.h"
typedef struct _gptimer
{
const char *name;
rt_hwtimer_t timer;
struct bflb_device_s *bflb_timer;
} _gptimer_t;
static void _hwtimer_init(rt_hwtimer_t *timer, rt_uint32_t state);
static rt_err_t _hwtimer_start(rt_hwtimer_t *timer, rt_uint32_t cnt, rt_hwtimer_mode_t mode);
static void _hwtimer_stop(rt_hwtimer_t *timer);
static rt_uint32_t _hwtimer_count_get(rt_hwtimer_t *timer);
static rt_err_t _hwtimer_control(rt_hwtimer_t *timer, rt_uint32_t cmd, void *args);
static void _hwtmr_isr(_gptimer_t *gptmr);
static const struct rt_hwtimer_ops _hwtimer_ops = {
.init = _hwtimer_init,
.start = _hwtimer_start,
.stop = _hwtimer_stop,
.count_get = _hwtimer_count_get,
.control = _hwtimer_control
};
static const struct rt_hwtimer_info _hwtimer_info = {
.maxfreq = 1000000UL,
.minfreq = 1000000UL,
.maxcnt = 0xFFFFFFFFUL,
.cntmode = HWTIMER_MODE_PERIOD
};
#ifdef BSP_USING_TIMER0
static _gptimer_t timer0 = {.name = "timer0"};
#endif /* BSP_USING_TIMER0 */
#ifdef BSP_USING_TIMER1
static _gptimer_t timer1 = {.name = "timer1" };
#endif /* BSP_USING_TIMER1 */
static _gptimer_t *s_gptimers[] = {
#ifdef BSP_USING_TIMER0
&timer0,
#endif /* BSP_USING_TIMER0 */
#ifdef BSP_USING_TIMER1
&timer1,
#endif /* BSP_USING_TIMER1 */
};
#ifdef BSP_USING_TIMER0
void timer0_isr(int irq, void *arg)
{
_hwtmr_isr(&timer0);
}
#endif /* BSP_USING_TIMER0 */
#ifdef BSP_USING_TIMER1
void timer1_isr(int irq, void *arg)
{
_hwtmr_isr(&timer1);
}
#endif /* BSP_USING_TIMER1 */
static void _hwtmr_isr(_gptimer_t *timer)
{
bool hwtmr_stat = bflb_timer_get_compint_status(timer->bflb_timer, TIMER_COMP_ID_0);
if (hwtmr_stat)
{
rt_device_hwtimer_isr(&timer->timer);
bflb_timer_compint_clear(timer->bflb_timer, TIMER_COMP_ID_0);
}
}
static void _hwtimer_init(rt_hwtimer_t *timer, rt_uint32_t state)
{
_gptimer_t *_gptmr = (_gptimer_t*)timer->parent.user_data;
struct bflb_timer_config_s cfg;
cfg.counter_mode = TIMER_COUNTER_MODE_PROLOAD;
cfg.clock_source = TIMER_CLKSRC_XTAL;
cfg.clock_div = 40;
cfg.trigger_comp_id = TIMER_COMP_ID_0;
cfg.comp0_val = 0;
cfg.comp1_val = 0;
cfg.comp2_val = 0;
cfg.preload_val = 0;
bflb_timer_init(_gptmr->bflb_timer, &cfg);
}
static rt_err_t _hwtimer_start(rt_hwtimer_t *timer, rt_uint32_t cnt, rt_hwtimer_mode_t mode)
{
_gptimer_t *_gptmr = (_gptimer_t*) timer->parent.user_data;
struct bflb_timer_config_s cfg;
if(mode == HWTIMER_MODE_ONESHOT)
cfg.counter_mode = TIMER_COUNTER_MODE_UP;
else
cfg.counter_mode = TIMER_COUNTER_MODE_PROLOAD;
cfg.clock_source = TIMER_CLKSRC_XTAL;
cfg.clock_div = 40;
cfg.trigger_comp_id = TIMER_COMP_ID_0;
cfg.comp0_val = cnt;
cfg.comp1_val = cnt;
cfg.comp2_val = cnt;
cfg.preload_val = 0;
bflb_timer_init(_gptmr->bflb_timer, &cfg);
bflb_irq_enable(_gptmr->bflb_timer->irq_num);
bflb_timer_start(_gptmr->bflb_timer);
return RT_EOK;
}
static void _hwtimer_stop(rt_hwtimer_t *timer)
{
_gptimer_t *_gptmr = (_gptimer_t*)timer->parent.user_data;
bflb_timer_stop(_gptmr->bflb_timer);
}
static rt_uint32_t _hwtimer_count_get(rt_hwtimer_t *timer)
{
_gptimer_t *_gptmr = (_gptimer_t*)timer->parent.user_data;
rt_uint32_t current_cnt = bflb_timer_get_countervalue(_gptmr->bflb_timer);
return current_cnt;
}
static rt_err_t _hwtimer_control(rt_hwtimer_t *timer, rt_uint32_t cmd, void *args)
{
rt_err_t err = RT_EOK;
_gptimer_t *_gptmr = (_gptimer_t*) timer->parent.user_data;
switch (cmd)
{
case HWTIMER_CTRL_FREQ_SET:
err = -RT_ERROR;
break;
case HWTIMER_CTRL_INFO_GET:
*(rt_hwtimer_t*)args = _gptmr->timer;
break;
case HWTIMER_CTRL_MODE_SET:
_gptmr->timer.mode = *(rt_uint32_t*)args;
break;
case HWTIMER_CTRL_STOP:
bflb_timer_stop(_gptmr->bflb_timer);
break;
}
return err;
}
int rt_hw_hwtimer_init(void)
{
int ret = RT_EOK;
for (uint32_t i = 0; i < sizeof(s_gptimers) / sizeof(s_gptimers[0]); i++)
{
s_gptimers[i]->timer.info = &_hwtimer_info;
s_gptimers[i]->timer.ops = &_hwtimer_ops;
s_gptimers[i]->bflb_timer = bflb_device_get_by_name(s_gptimers[i]->name);
ret = rt_device_hwtimer_register(&s_gptimers[i]->timer, s_gptimers[i]->name, s_gptimers[i]);
if (ret != RT_EOK)
{
LOG_E("%s register failed", s_gptimers[i]->name);
}
}
#ifdef BSP_USING_TIMER0
bflb_irq_attach(bflb_device_get_by_name("timer0")->irq_num, timer0_isr, NULL);
#endif /* BSP_USING_TIMER0 */
#ifdef BSP_USING_TIMER1
bflb_irq_attach(bflb_device_get_by_name("timer1")->irq_num, timer1_isr, NULL);
#endif /* BSP_USING_TIMER1 */
return ret;
}
INIT_DEVICE_EXPORT(rt_hw_hwtimer_init);
#endif /* RT_USING_HWTIMER */
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2023-04-01 wcx1024979076 first version
*/
#ifndef DRV_HWTIMER_H
#define DRV_HWTIMER_H
#include "bflb_timer.h"
#include "bflb_mtimer.h"
#include "board.h"
int rt_hw_hwtimer_init(void);
#endif /* DRV_HWTIMER_H */
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册