一、前言
由于硬件SPI目前还未正式加入软件包,只出了一个示例,该示例可以直接运行。
但我的工程是基于 1.0.9 版本的SDK建立的,直接使用该示例的demo会报错,所以根据这个示例包做一下修改,添加硬件SPI使用。
![1.jpg](//file.elecfans.com/web2/M00/7D/AC/poYBAGOAZ-2AOQuVAAA1g5hJnTk490.jpg)
二、替换步骤
1、复制demo源文件
driver_common.h、driver_spi.h、spi_test.c 三个文件复制到 applications 文件夹。
2、替换 packages\bluetrum_sdk-latest 下的 libhal.a 静态库
![1.jpg](//file.elecfans.com/web2/M00/7E/38/pYYBAGOAaAKAdKviAAAj2IDoOHg555.jpg)
3、修改 ab32vg1_hal.h
![1.jpg](//file.elecfans.com/web2/M00/7D/AC/poYBAGOAaBaAQ-LrAABGI46ml7o564.jpg)
/*
Copyright (c) 2020-2020, BLUETRUM Development Team
SPDX-License-Identifier: Apache-2.0
*/
#ifndef AB32VG1_HAL_H__
#define AB32VG1_HAL_H__
#include "ab32vg1_hal_conf.h"
void hal_set_tick_hook(void (*hook)(uint32_t ticks));
void hal_set_ticks(uint32_t ticks);
uint32_t hal_get_ticks(void);
void hal_mdelay(uint32_t nms);
void hal_udelay(uint32_t nus);
void hal_printf(const char *fmt, ...);
#endif
4、修改 ab32vg1_hal.c
![1.jpg](//file.elecfans.com/web2/M00/7E/38/pYYBAGOAaDKAQwLIAABKPqN4xl8359.jpg)
#include "ab32vg1_hal.h"
static uint32_t hw_ticks = 0;
static void (*tick_cfg_hook)(uint32_t ticks) = HAL_NULL;
void hal_set_tick_hook(void (*hook)(uint32_t ticks))
{
tick_cfg_hook = hook;
}
void hal_set_ticks(uint32_t ticks)
{
if (ticks != hw_ticks) {
hw_ticks = ticks;
}
if (tick_cfg_hook != HAL_NULL) {
tick_cfg_hook(hw_ticks);
}
}
WEAK void hal_mdelay(uint32_t nms)
{
}
WEAK void hal_udelay(uint32_t nus)
{
}
WEAK void hal_printf(const char *fmt, ...)
{
}
5、修改 board.c
![1.jpg](//file.elecfans.com/web2/M00/7E/38/pYYBAGOAaFOACzSnAAEqilePEs8088.jpg)
![2.jpg](//file.elecfans.com/web2/M00/7D/AC/poYBAGOAaFaAJdByAAEj0DEGiaM463.jpg)
/*
Copyright (c) 2020-2021, Bluetrum Development Team
SPDX-License-Identifier: Apache-2.0
Change Logs:
Date Author Notes
2020-11-18 greedyhao first version
*/
#include <rthw.h>
#include "board.h"
int rt_hw_usart_init(void);
void my_printf(const char *format, ...);
void my_print_r(const void *buf, uint16_t cnt);
void timer0_cfg(uint32_t ticks);
void rt_soft_isr(int vector, void *param);
void cpu_irq_comm(void);
void set_cpu_irq_comm(void (*irq_hook)(void));
void load_cache();
void os_cache_init(void);
void sys_error_hook(uint8_t err_no);
void huart_timer_isr(void);
typedef void (*spiflash_init_func)(uint8_t sf_read, uint8_t dummy);
static struct rt_mutex mutex_spiflash = {0};
static struct rt_mutex mutex_cache = {0};
extern volatile rt_uint8_t rt_interrupt_nest;
extern uint32_t __heap_start, __heap_end;
#ifdef RT_USING_CONSOLE
void hal_printf(const char fmt, ...)
{
rt_device_t console = rt_console_get_device();
va_list args;
rt_size_t length;
static char rt_log_buf[RT_CONSOLEBUF_SIZE];
va_start(args, fmt);
/ the return value of vsnprintf is the number of bytes that would be
written to buffer had if the size of the buffer been sufficiently
large excluding the terminating null byte. If the output string
would be larger than the rt_log_buf, we have to adjust the output
length. */
length = rt_vsnprintf(rt_log_buf, sizeof(rt_log_buf) - 1, fmt, args);
if (length > RT_CONSOLEBUF_SIZE - 1)
length = RT_CONSOLEBUF_SIZE - 1;
#ifdef RT_USING_DEVICE
if (console == RT_NULL)
{
rt_hw_console_output(rt_log_buf);
}
else
{
rt_uint16_t old_flag = console->open_flag;
console->open_flag |= RT_DEVICE_FLAG_STREAM;
rt_device_write(console, 0, rt_log_buf, length);
console->open_flag = old_flag;
}
#else
rt_hw_console_output(rt_log_buf);
#endif
va_end(args);
}
#endif
RT_SECTION(".irq")
void os_interrupt_enter(void)
{
rt_interrupt_enter();
}
RT_SECTION(".irq")
void os_interrupt_leave(void)
{
rt_interrupt_leave();
}
typedef void (isr_t)(void);
RT_SECTION(".irq")
isr_t register_isr(int vector, isr_t isr)
{
char buf[8] = {0};
rt_snprintf(buf, sizeof(buf), "sys%d", vector);
rt_isr_handler_t handle = (rt_isr_handler_t)isr;
rt_hw_interrupt_install(vector, handle, RT_NULL, buf);
}
RT_SECTION(".irq.timer")
void timer0_isr(int vector, void param)
{
rt_interrupt_enter();
TMR0CPND = BIT(9);
rt_tick_increase();
#ifdef RT_USING_SERIAL
huart_timer_isr();
#endif
rt_interrupt_leave();
}
void timer0_init(void)
{
TMR0CON = BIT(7); //TIE
TMR0CNT = 0;
rt_hw_interrupt_install(IRQ_TMR0_VECTOR, timer0_isr, RT_NULL, "tick");
}
void timer0_cfg(uint32_t ticks)
{
TMR0PR = (uint32_t)(ticks - 1UL); //1ms interrupt
TMR0CON |= BIT(0); // EN
}
uint32_t hal_get_ticks(void)
{
return rt_tick_get();
}
void hal_mdelay(uint32_t nms)
{
rt_thread_mdelay(nms);
}
void hal_udelay(uint32_t nus)
{
rt_hw_us_delay(nus);
}
/
The time delay function.
[url=home.php?mod=space&uid=3142012]@param[/url] us microseconds.
/
RT_SECTION(".com_text")
void rt_hw_us_delay(rt_uint32_t us)
{
rt_uint32_t ticks;
rt_uint32_t told, tnow, tcnt = 0;
rt_uint32_t reload = TMR0PR;
ticks = us * reload / (1000 / RT_TICK_PER_SECOND);
told = TMR0CNT;
while (1)
{
tnow = TMR0CNT;
if (tnow != told)
{
if (tnow < told)
{
tcnt += told - tnow;
}
else
{
tcnt += reload - tnow + told;
}
told = tnow;
if (tcnt >= ticks)
{
break;
}
}
}
}
void rt_hw_systick_init(void)
{
CLKCON2 &= 0x00ffffff;
CLKCON2 |= (25 << 24); //配置x26m_div_clk = 1M (timer, ir, fmam ...用到)
CLKCON0 &= ~(7 << 23);
CLKCON0 |= BIT(24); //tmr_inc select x26m_div_clk = 1M
set_sysclk(SYSCLK_48M);
/ Setting software interrupt */
set_cpu_irq_comm(cpu_irq_comm);
rt_hw_interrupt_install(IRQ_SW_VECTOR, rt_soft_isr, RT_NULL, "sw_irq");
timer0_init();
hal_set_tick_hook(timer0_cfg);
hal_set_ticks(get_sysclk_nhz()/RT_TICK_PER_SECOND);
PICCON |= 0x10002;
}
void rt_hw_board_init(void)
{
WDT_DIS();
rt_hw_systick_init();
#ifdef RT_USING_HEAP
rt_system_heap_init(&__heap_start, &__heap_end);
#endif
#ifdef RT_USING_PIN
rt_hw_pin_init();
#endif // RT_USING_PIN
#ifdef RT_USING_SERIAL
rt_hw_usart_init();
#endif // RT_USING_SERIAL
#ifdef RT_USING_CONSOLE
rt_console_set_device(RT_CONSOLE_DEVICE_NAME);
#endif // RT_USING_CONSOLE
#ifdef RT_USING_COMPONENTS_INIT
rt_components_board_init();
#endif
}
RT_SECTION(".irq.cache")
void cache_init(void)
{
os_cache_init();
rt_mutex_init(&mutex_spiflash, "flash_mutex", RT_IPC_FLAG_FIFO);
rt_mutex_init(&mutex_cache, "cache_mutex", RT_IPC_FLAG_FIFO);
}
RT_SECTION(".irq.cache")
void os_spiflash_lock(void)
{
// if (rt_thread_self()->stat == RT_THREAD_RUNNING) {
if ((rt_thread_self() != RT_NULL) && (rt_interrupt_nest == 0)) {
rt_mutex_take(&mutex_spiflash, RT_WAITING_FOREVER);
}
}
RT_SECTION(".irq.cache")
void os_spiflash_unlock(void)
{
// if (rt_thread_self()->stat == RT_THREAD_RUNNING) {
if ((rt_thread_self() != RT_NULL) && (rt_interrupt_nest == 0)) {
rt_mutex_release(&mutex_spiflash);
}
}
RT_SECTION(".irq.cache")
void os_cache_lock(void)
{
// if (rt_thread_self()->stat == RT_THREAD_RUNNING) {
if ((rt_thread_self() != RT_NULL) && (rt_interrupt_nest == 0)) {
rt_mutex_take(&mutex_cache, RT_WAITING_FOREVER);
}
}
RT_SECTION(".irq.cache")
void os_cache_unlock(void)
{
// if (rt_thread_self()->stat == RT_THREAD_RUNNING) {
if ((rt_thread_self() != RT_NULL) && (rt_interrupt_nest == 0)) {
rt_mutex_release(&mutex_cache);
}
}
RT_SECTION(".irq.err.str")
static const char stack_info[] = "thread sp=0x%x name=%s";
void rt_hw_console_output(const char *str)
{
my_printf(str);
}
/**
[url=home.php?mod=space&uid=2666770]@Brief[/url] print exception error
[url=home.php?mod=space&uid=1902110]@NOTE[/url] Every message needed to print, must put in .comm exction.
*/
RT_SECTION(".irq.err")
void exception_isr(void)
{
#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS)
extern long list_thread(void);
#endif
sys_error_hook(1);
#ifdef RT_USING_CONSOLE
rt_console_set_device(RT_NULL);
rt_kprintf(stack_info, rt_thread_self()->sp, rt_thread_self()->name);
#endif
while(1);
}
三、编译
再次编译就不会报错了:
![1.jpg](//file.elecfans.com/web2/M00/7D/AD/poYBAGOAaYKAWMz0AABljcCu_gs635.jpg)
四、烧录测试
烧录完执行 spi_test 测试,代码里可切换master和slave模式。
![1.jpg](//file.elecfans.com/web2/M00/7D/AD/poYBAGOAaZCAGVZkAADKso7ilLo946.jpg)
原作者:丨晋丨