Merge branch 'prepare_for_master' of https://git.trustie.net/xuos/xiuos into control_framework

This commit is contained in:
Liu_Weichao
2022-11-18 09:52:41 +08:00
204 changed files with 27515 additions and 669 deletions
@@ -48,7 +48,7 @@ Modification:
; <o> Stack Size (in Bytes) <0x0-0xFFFFFFFF:8>
;</h>
*/
.equ Stack_Size, 0x00002000
.equ Stack_Size, 0x00004000
.section .stack
.align 3
@@ -60,26 +60,6 @@ __StackLimit:
__StackTop:
.size __StackTop, . - __StackTop
/*
;<h> Heap Configuration
; <o> Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
;</h>
*/
.equ Heap_Size, 0x00002000
.if Heap_Size != 0 /* Heap is provided */
.section .heap
.align 3
.globl __HeapBase
.globl __HeapLimit
__HeapBase:
.space Heap_Size
.size __HeapBase, . - __HeapBase
__HeapLimit:
.size __HeapLimit, . - __HeapLimit
.endif
/*
;<h> Reset handler start.
*/
@@ -35,9 +35,11 @@ menu "aiit-arm32-board feature"
menu "config board peripheral"
config MOUNT_SDCARD
bool "mount cd card"
bool
default n
config MOUNT_USB
bool
default n
select BSP_USING_SDIO
endmenu
endmenu
endmenu
@@ -51,6 +51,7 @@ extern int HwSramInit(void);
extern int Stm32HwAdcInit(void);
extern int Stm32HwDacInit(void);
extern int Stm32HwLcdInit(void);
extern int Stm32HwUsbInit(void);
static void ClockConfiguration()
{
@@ -147,6 +148,11 @@ struct InitSequenceDesc _board_init[] =
#ifdef BSP_USING_SDIO
{"hw sdcard init",HwSdioInit},
#endif
#ifdef BSP_USING_USB
#ifdef BSP_USING_STM32_USBH
{ "hw usb", Stm32HwUsbInit },
#endif
#endif
#ifdef BSP_USING_EXTMEM
{ "hw extern sram", HwSramInit },
#endif
@@ -396,7 +396,7 @@ static const struct LoraDevDone lora_done =
* @param bus_name spi bus name
* @param dev_name spi dev name
* @param drv_name spi drv name
* @param flash_name flash dev name
* @param lora_name lora name
*/
SpiLoraDeviceType SpiLoraInit(char *bus_name, char *dev_name, char *drv_name, char *lora_name)
{
@@ -493,7 +493,7 @@ int LoraSx12xxSpiDeviceInit(void)
return EOK;
}
//#define LORA_TEST
#define LORA_TEST
#ifdef LORA_TEST
/*Just for lora test*/
static struct Bus *bus;
@@ -504,11 +504,11 @@ void LoraOpen(void)
{
x_err_t ret = EOK;
ret = LoraSx12xxSpiDeviceInit();
if (EOK != ret) {
KPrintf("LoraSx12xxSpiDeviceInit failed\n");
return;
}
// ret = LoraSx12xxSpiDeviceInit();
// if (EOK != ret) {
// KPrintf("LoraSx12xxSpiDeviceInit failed\n");
// return;
// }
bus = BusFind(SPI_BUS_NAME_2);
dev = BusFindDevice(bus, SX12XX_DEVICE_NAME);
@@ -103,7 +103,7 @@ static x_err_t Stm32SpiInit(struct Stm32Spi *SpiDrv, struct SpiMasterParam *cfg)
SPI_InitTypeDef *SpiInit = &SpiDrv->init;
if (cfg->spi_work_mode & DEV_SPI_SLAVE)
if (cfg->spi_work_mode & SPI_DEV_SLAVE)
{
SpiInit->SPI_Mode = SPI_Mode_Slave;
}
@@ -784,12 +784,12 @@ uint32_t SX1276LoraChannelEmpty( void )
if(result == RF_CHANNEL_EMPTY)
{
KPrintf("\nLora--信道可用(RF_CHANNEL_EMPTY\n");
KPrintf("\nLora--RF_CHANNEL_EMPTY\n");
return 0;
}
else if(result == RF_CHANNEL_ACTIVITY_DETECTED)
{
KPrintf("\nLora--信道正被占用(RF_CHANNEL_ACTIVITY_DETECTED\n");
KPrintf("\nLora--RF_CHANNEL_ACTIVITY_DETECTED\n");
return 1;
}
else
@@ -1,6 +1,6 @@
config BSP_USING_STM32_USBH
bool "Using usb host"
default y
default n
if BSP_USING_STM32_USBH
config USB_BUS_NAME
string "usb bus name"
@@ -11,5 +11,15 @@ config BSP_USING_STM32_USBH
config USB_DEVICE_NAME
string "usb bus device name"
default "usb_dev"
config MOUNT_USB_FS
bool "mount usb file system"
default y
select MOUNT_USB
if MOUNT_USB_FS
config MOUNT_USB_FS_TYPE
int "choose file system type : FATFS(0) LWEXT4(3)"
default 0
endif
endif
@@ -25,6 +25,14 @@
uint32 UdiskRead_new_api(void *dev, struct BusBlockReadParam *read_param);
uint32 UdiskWirte_new_api(void *dev, struct BusBlockWriteParam *write_param);
#ifdef MOUNT_USB
int MountUsb(void)
{
STM32USBHostRegister();
return 0;
}
#endif
static uint32 UdiskOpenNewApi(void *dev)
{
return EOK;
@@ -37,7 +37,7 @@ menu "aiit-riscv64-board feature"
menu "config board peripheral"
config MOUNT_SDCARD
bool "mount cd card"
bool "mount sd card"
default n
select BSP_USING_SDIO
config MOUNT_USB
@@ -71,7 +71,7 @@ extern int HwCh376Init(void);
* @description: Mount USB
* @return 0
*/
int MountUSB(void)
int MountUsb(void)
{
if (MountFilesystem(USB_BUS_NAME, USB_DEVICE_NAME, USB_DRIVER_NAME, FSTYPE_CH376, "/") == 0)
KPrintf("usb mount to '/'");
@@ -389,7 +389,7 @@ static const struct LoraDevDone lora_done =
* @param bus_name spi bus name
* @param dev_name spi dev name
* @param drv_name spi drv name
* @param flash_name flash dev name
* @param lora_name lora name
*/
SpiLoraDeviceType SpiLoraInit(char *bus_name, char *dev_name, char *drv_name, char *lora_name)
{
@@ -221,7 +221,7 @@ static uint32 SpiReadData(struct SpiHardwareDevice *spi_dev, struct SpiDataStand
{
SpiDeviceParam *dev_param = (SpiDeviceParam *)(spi_dev->haldev.private_data);
uint32 spi_read_length = 0;;
uint32 spi_read_length = 0;
uint8 device_id = dev_param->spi_slave_param->spi_slave_id;
uint8 device_master_id = dev_param->spi_dma_param->spi_master_id;
uint8 cs_gpio_pin = dev_param->spi_slave_param->spi_cs_gpio_pin;
@@ -394,9 +394,15 @@ static int BoardSpiDevBend(struct SpiDmaParam *spi_initparam)
static struct SpiHardwareDevice spi_device2;
memset(&spi_device2, 0, sizeof(struct SpiHardwareDevice));
spi_initparam->spi_slave_id[SPI_DEVICE_SLAVE_ID_2] = SPI_DEVICE_SLAVE_ID_2;
spi_initparam->spi_cs_gpio_pin[SPI_DEVICE_SLAVE_ID_2] = SPI1_CS2_PIN;
spi_initparam->spi_cs_select_id[SPI_DEVICE_SLAVE_ID_2] = SPI_CHIP_SELECT_2;
static struct SpiSlaveParam spi_slaveparam2;
memset(&spi_slaveparam2, 0, sizeof(struct SpiSlaveParam));
spi_slaveparam2.spi_slave_id = SPI_DEVICE_SLAVE_ID_2;
spi_slaveparam2.spi_cs_gpio_pin = SPI1_CS2_PIN;
spi_slaveparam2.spi_cs_select_id = SPI_CHIP_SELECT_2;
spi_device2.spi_param.spi_dma_param = spi_initparam;
spi_device2.spi_param.spi_slave_param = &spi_slaveparam2;
spi_device2.spi_dev_done = &(spi_dev_done);
@@ -417,9 +423,15 @@ static int BoardSpiDevBend(struct SpiDmaParam *spi_initparam)
static struct SpiHardwareDevice spi_device3;
memset(&spi_device3, 0, sizeof(struct SpiHardwareDevice));
spi_initparam->spi_slave_id[SPI_DEVICE_SLAVE_ID_3] = SPI_DEVICE_SLAVE_ID_3;
spi_initparam->spi_cs_gpio_pin[SPI_DEVICE_SLAVE_ID_3] = SPI1_CS3_PIN;
spi_initparam->spi_cs_select_id[SPI_DEVICE_SLAVE_ID_3] = SPI_CHIP_SELECT_3;
static struct SpiSlaveParam spi_slaveparam3;
memset(&spi_slaveparam3, 0, sizeof(struct SpiSlaveParam));
spi_slaveparam3.spi_slave_id = SPI_DEVICE_SLAVE_ID_3;
spi_slaveparam3.spi_cs_gpio_pin = SPI1_CS3_PIN;
spi_slaveparam3.spi_cs_select_id = SPI_CHIP_SELECT_3;
spi_device3.spi_param.spi_dma_param = spi_initparam;
spi_device3.spi_param.spi_slave_param = &spi_slaveparam3;
spi_device3.spi_dev_done = &(spi_dev_done);
@@ -784,12 +784,12 @@ uint32_t SX1276LoraChannelEmpty( void )
if(result == RF_CHANNEL_EMPTY)
{
KPrintf("\nLora--信道可用(RF_CHANNEL_EMPTY\n");
KPrintf("\nLora--RF_CHANNEL_EMPTY\n");
return 0;
}
else if(result == RF_CHANNEL_ACTIVITY_DETECTED)
{
KPrintf("\nLora--信道正被占用(RF_CHANNEL_ACTIVITY_DETECTED\n");
KPrintf("\nLora--RF_CHANNEL_ACTIVITY_DETECTED\n");
return 1;
}
else
@@ -32,16 +32,16 @@ CONFIG_BSP_USING_UART_HS=y
#
# General Purpose UARTs
#
CONFIG_BSP_USING_UART1=y
CONFIG_BSP_UART1_TXD_PIN=20
CONFIG_BSP_UART1_RXD_PIN=21
CONFIG_BSP_USING_UART2=y
CONFIG_BSP_UART2_TXD_PIN=28
CONFIG_BSP_UART2_RXD_PIN=27
CONFIG_BSP_USING_UART3=y
CONFIG_BSP_UART3_TXD_PIN=22
CONFIG_BSP_UART3_RXD_PIN=23
CONFIG___STACKSIZE__=4096
# CONFIG_BSP_USING_UART1=y
# CONFIG_BSP_UART1_TXD_PIN=20
# CONFIG_BSP_UART1_RXD_PIN=21
# CONFIG_BSP_USING_UART2=y
# CONFIG_BSP_UART2_TXD_PIN=28
# CONFIG_BSP_UART2_RXD_PIN=27
# CONFIG_BSP_USING_UART3=y
# CONFIG_BSP_UART3_TXD_PIN=22
# CONFIG_BSP_UART3_RXD_PIN=23
# CONFIG___STACKSIZE__=4096
#
# Hardware feature
+43 -15
View File
@@ -44,10 +44,14 @@ Modification:
#include "fpioa.h"
#include "dmac.h"
#include "connect_gpio.h"
#include "connect_soft_spi.h"
#include "connect_rtc.h"
#include "connect_hwtimer.h"
#include "connect_wdt.h"
#if defined(FS_VFS)
#include <iot-vfs.h>
#endif
// #if defined(FS_VFS)
// #include <iot-vfs.h>
// #endif
#define CPU0 (0)
#define CPU1 (1)
@@ -60,15 +64,15 @@ extern int HwTouchInit(void);
extern int HwCh376Init(void);
extern int HwLcdInit(void);
extern int HwSpiInit(void);
extern int HwSoftSPIInit(void);
#ifdef FS_CH376
#include <iot-vfs.h>
#ifdef MOUNT_USB
/**
* @description: Mount USB
* @return 0
*/
int MountUSB(void)
int MountUsb(void)
{
if (MountFilesystem(USB_BUS_NAME, USB_DEVICE_NAME, USB_DRIVER_NAME, FSTYPE_CH376, "/") == 0)
KPrintf("usb mount to '/'\n");
@@ -78,23 +82,34 @@ int MountUSB(void)
return 0;
}
#endif
#ifdef MOUNT_SDCARD
#if defined(FS_VFS) && defined (MOUNT_SDCARD)
#include <iot-vfs.h>
#include <sd_spi.h>
extern SpiSdDeviceType SpiSdInit(struct Bus *bus, const char *dev_name, const char *drv_name, const char *sd_name);
/**
* @description: Mount SD card
* @return 0
*/
int MountSDCard(void)
int MountSDCard(void)
{
if (MountFilesystem(SDIO_BUS_NAME,SDIO_DEVICE_NAME ,SDIO_DRIVER_NAME , FSTYPE_CH376, "/") == 0)
KPrintf("sd card mount to '/'\n");
else
KPrintf("sd card mount to '/' failed!\n");
return 0;
struct Bus *spi_bus;
spi_bus = BusFind(SOFT_SPI_BUS_NAME);
if (NONE == SpiSdInit(spi_bus, SOFT_SPI_DEVICE_NAME, SOFT_SPI_DRV_NAME, SPI_SD_NAME)) {
KPrintf("MountSDCard SpiSdInit error!\n");
return -1;
}
if (EOK != MountFilesystem(SOFT_SPI_BUS_NAME, SPI_SD_NAME, SOFT_SPI_DRV_NAME, FSTYPE_FATFS, "/")) {
return -1;
}
KPrintf("SPI SD card fatfs mounted\n");
return 0;
}
#endif
#endif
void InitBss(void)
{
@@ -172,6 +187,9 @@ struct InitSequenceDesc _board_init[] =
#ifdef BSP_USING_I2C
{ "hw_i2c", HwI2cInit },
#endif
#ifdef BSP_USING_RTC
{ "hw_rtc", HwRtcInit },
#endif
#ifdef BSP_USING_SPI
{ "hw_spi", HwSpiInit },
#endif
@@ -183,10 +201,20 @@ struct InitSequenceDesc _board_init[] =
#endif
#ifdef BSP_USING_TOUCH
{"touch", HwTouchInit },
#endif
#ifdef BSP_USING_SOFT_SPI
{"soft_spi", HwSoftSPIInit },
#endif
#ifdef BSP_USING_HWTIMER
{"hw_timer", HwTimerInit },
#endif
#ifdef BSP_USING_WDT
{"hw_wdt", HwWdtInit },
#endif
{ " NONE ",NONE },
};
void InitBoardHardware(void)
{
int i = 0;
@@ -16,6 +16,16 @@ menuconfig BSP_USING_SPI
source "$BSP_DIR/third_party_driver/spi/Kconfig"
endif
menuconfig BSP_USING_SOFT_SPI
bool "Using SOFT_SPI device"
default n
select BSP_USING_SPI
select MOUNT_SDCARD
select FS_VFS
if BSP_USING_SOFT_SPI
source "$BSP_DIR/third_party_driver/soft_spi/Kconfig"
endif
menuconfig BSP_USING_LCD
bool "Using LCD device"
default n
@@ -78,3 +88,27 @@ menuconfig BSP_USING_UART
if BSP_USING_UART
source "$BSP_DIR/third_party_driver/uart/Kconfig"
endif
menuconfig BSP_USING_RTC
bool "Using RTC device"
default y
select RESOURCES_RTC
if BSP_USING_RTC
source "$BSP_DIR/third_party_driver/rtc/Kconfig"
endif
menuconfig BSP_USING_HWTIMER
bool "Using TIMER device"
default y
select RESOURCES_HWTIMER
if BSP_USING_HWTIMER
source "$BSP_DIR/third_party_driver/timer/Kconfig"
endif
menuconfig BSP_USING_WDT
bool "Using WATCHDOG device"
default y
select RESOURCES_WDT
if BSP_USING_WDT
source "$BSP_DIR/third_party_driver/watchdog/Kconfig"
endif
@@ -40,4 +40,21 @@ ifeq ($(CONFIG_BSP_USING_LCD),y)
SRC_DIR += lcd
endif
ifeq ($(CONFIG_BSP_USING_SOFT_SPI),y)
SRC_DIR += soft_spi
endif
ifeq ($(CONFIG_BSP_USING_RTC),y)
SRC_DIR += rtc
endif
ifeq ($(CONFIG_BSP_USING_HWTIMER),y)
SRC_DIR += timer
endif
ifeq ($(CONFIG_BSP_USING_WDT),y)
SRC_DIR += watchdog
endif
include $(KERNEL_ROOT)/compiler.mk
@@ -75,12 +75,13 @@ static struct io_config
IOCONFIG(BSP_UART3_TXD_PIN, FUNC_UART3_RX),
IOCONFIG(BSP_UART3_RXD_PIN, FUNC_UART3_TX),
#endif
#ifdef BSP_USING_I2C1
#ifdef BSP_USING_I2C
IOCONFIG(BSP_I2C_SDA, FUNC_GPIO3),
IOCONFIG(BSP_I2C_SCL, FUNC_GPIO4),
#endif
#ifdef BSP_USING_TOUCH
IOCONFIG(BSP_TOUCH_TP_INT, HS_GPIO(FPIOA_TOUCH_TP_INT)),
// IOCONFIG(BSP_TOUCH_TP_INT, HS_GPIO(FPIOA_TOUCH_TP_INT)),
IOCONFIG(BSP_TOUCH_TP_INT, HS_GPIO(FUNC_GPIOHS30)),
#endif
#ifdef BSP_USING_CH438
@@ -95,7 +96,31 @@ static struct io_config
IOCONFIG(BSP_CH438_D4_PIN, HS_GPIO(FPIOA_CH438_D4)),
IOCONFIG(BSP_CH438_D5_PIN, HS_GPIO(FPIOA_CH438_D5)),
IOCONFIG(BSP_CH438_D6_PIN, HS_GPIO(FPIOA_CH438_D6)),
IOCONFIG(BSP_CH438_D7_PIN, HS_GPIO(FPIOA_CH438_D7))
IOCONFIG(BSP_CH438_D7_PIN, HS_GPIO(FPIOA_CH438_D7)),
#endif
#ifdef BSP_USING_SOFT_SPI
IOCONFIG(BSP_SOFT_SPI_SCK_PIN, HS_GPIO(FPIOA_SOFT_SPI_SCK)),
IOCONFIG(BSP_SOFT_SPI_MIOS_PIN, HS_GPIO(FPIOA_SOFT_SPI_MIOS)),
IOCONFIG(BSP_SOFT_SPI_MSOI_PIN, HS_GPIO(FPIOA_SOFT_SPI_MSOI)),
IOCONFIG(BSP_SOFT_SPI_NCS_PIN, HS_GPIO(FPIOA_SOFT_SPI_NCS)),
#endif
#ifdef BSP_USING_LORA
IOCONFIG(BSP_E220_M0_PIN, HS_GPIO(FUNC_GPIOHS10)),
IOCONFIG(BSP_E220_M1_PIN, HS_GPIO(FUNC_GPIOHS11)),
#endif
#ifdef BSP_USING_RS485
IOCONFIG(BSP_485_DIR_PIN,HS_GPIO(FUNC_GPIOHS12));
#endif
#ifdef BSP_USING_LED
IOCONFIG(BSP_LED_PIN,FUNC_GPIO5);
#endif
#ifdef BSP_USING_KEY
IOCONFIG(BSP_KEY_PIN,FUNC_GPIO6);
#endif
};
@@ -12,6 +12,6 @@ if BSP_USING_I2C
string "i2c bus 1 driver name"
default "i2c1_drv"
config I2C_1_DEVICE_NAME_0
string "i2c bus 1 device 0 name"
default "i2c1_dev0"
string "i2c bus 1 device 0 name"
default "i2c1_dev0"
endif
@@ -0,0 +1,37 @@
/*
* Copyright (c) 2020 AIIT XUOS Lab
* XiUOS is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
/**
* @file connect_hwtimer.h
* @brief define aiit-riscv64-board hwtimer function and struct
* @version 1.0
* @author AIIT XUOS Lab
* @date 2021-04-25
*/
#ifndef CONNECT_HWTIMER_H
#define CONNECT_HWTIMER_H
#include <device.h>
#include "hardware_hwtimer.h"
#ifdef __cplusplus
extern "C" {
#endif
int HwTimerInit(void);
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,36 @@
/*
* Copyright (c) 2020 AIIT XUOS Lab
* XiUOS is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
/**
* @file connect_rtc.h
* @brief define aiit-riscv64-board rtc function and struct
* @version 1.0
* @author AIIT XUOS Lab
* @date 2021-04-25
*/
#ifndef CONNECT_RTC_H
#define CONNECT_RTC_H
#include <device.h>
#ifdef __cplusplus
extern "C" {
#endif
int HwRtcInit(void);
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,14 @@
#ifndef CONNECT_TF_H
#define CONNECT_TF_H
#ifdef __cplusplus
extern "C" {
#endif
int HwSoftSPIInit(void);
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,36 @@
/*
* Copyright (c) 2020 AIIT XUOS Lab
* XiUOS is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
/**
* @file connect_wdt.h
* @brief define aiit-riscv64-board wdt function and struct
* @version 1.0
* @author AIIT XUOS Lab
* @date 2021-04-25
*/
#ifndef CONNECT_WDT_H
#define CONNECT_WDT_H
#include <device.h>
#ifdef __cplusplus
extern "C" {
#endif
int HwWdtInit(void);
#ifdef __cplusplus
}
#endif
#endif
@@ -78,6 +78,36 @@ enum HS_GPIO_CONFIG
#define BSP_CH438_INT_PIN 35
#endif
#ifdef BSP_USING_SOFT_SPI
#define FPIOA_SOFT_SPI_SCK 26
#define FPIOA_SOFT_SPI_MIOS 25
#define FPIOA_SOFT_SPI_MSOI 27
#define FPIOA_SOFT_SPI_NCS 28
#define BSP_SOFT_SPI_SCK_PIN 26
#define BSP_SOFT_SPI_MIOS_PIN 25
#define BSP_SOFT_SPI_MSOI_PIN 27
#define BSP_SOFT_SPI_NCS_PIN 28
#endif
#ifdef BSP_USING_LED
#define BSP_LED_PIN 29
#endif
#ifdef BSP_USING_KEY
#define BSP_KEY_PIN 31
#endif
#ifdef BSP_USING_LORA
#define BSP_E220_M0_PIN 32
#define BSP_E220_M1_PIN 33
#endif
#ifdef BSP_USING_RS485
#define BSP_485_DIR_PIN 24
#endif
extern int IoConfigInit(void);
#endif
@@ -0,0 +1,171 @@
/* Copyright 2018 Canaan Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @file hardware_hwtimer.h
* @brief add from Canaan k210 SDK
* https://canaan-creative.com/developer
* @version 1.0
* @author AIIT XUOS Lab
* @date 2021-04-25
*/
#ifndef __HARDWARE_HWTIMER_H__
#define __HARDWARE_HWTIMER_H__
#include <stdint.h>
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
/* clang-format off */
typedef struct _timer_channel
{
/* TIMER_N Load Count Register (0x00+(N-1)*0x14) */
volatile uint32_t load_count;
/* TIMER_N Current Value Register (0x04+(N-1)*0x14) */
volatile uint32_t current_value;
/* TIMER_N Control Register (0x08+(N-1)*0x14) */
volatile uint32_t control;
/* TIMER_N Interrupt Clear Register (0x0c+(N-1)*0x14) */
volatile uint32_t eoi;
/* TIMER_N Interrupt Status Register (0x10+(N-1)*0x14) */
volatile uint32_t intr_stat;
} __attribute__((packed, aligned(4))) timer_channel_t;
typedef struct _kendryte_timer
{
/* TIMER_N Register (0x00-0x4c) */
volatile timer_channel_t channel[4];
/* reserverd (0x50-0x9c) */
volatile uint32_t resv1[20];
/* TIMER Interrupt Status Register (0xa0) */
volatile uint32_t intr_stat;
/* TIMER Interrupt Clear Register (0xa4) */
volatile uint32_t eoi;
/* TIMER Raw Interrupt Status Register (0xa8) */
volatile uint32_t raw_intr_stat;
/* TIMER Component Version Register (0xac) */
volatile uint32_t comp_version;
/* TIMER_N Load Count2 Register (0xb0-0xbc) */
volatile uint32_t load_count2[4];
} __attribute__((packed, aligned(4))) kendryte_timer_t;
typedef enum _timer_deivce_number
{
TIMER_DEVICE_0,
TIMER_DEVICE_1,
TIMER_DEVICE_2,
TIMER_DEVICE_MAX,
} timer_device_number_t;
typedef enum _timer_channel_number
{
TIMER_CHANNEL_0,
TIMER_CHANNEL_1,
TIMER_CHANNEL_2,
TIMER_CHANNEL_3,
TIMER_CHANNEL_MAX,
} timer_channel_number_t;
/* TIMER Control Register */
#define TIMER_CR_ENABLE 0x00000001
#define TIMER_CR_MODE_MASK 0x00000002
#define TIMER_CR_FREE_MODE 0x00000000
#define TIMER_CR_USER_MODE 0x00000002
#define TIMER_CR_INTERRUPT_MASK 0x00000004
#define TIMER_CR_PWM_ENABLE 0x00000008
/* clang-format on */
extern volatile kendryte_timer_t *const timer[3];
/**
* @brief Definitions for the timer callbacks
*/
typedef int (*timer_callback_t)(void *ctx);
/**
* @brief Set timer timeout
*
* @param[in] timer timer
* @param[in] channel channel
* @param[in] nanoseconds timeout
*
* @return the real timeout
*/
size_t timer_set_interval(timer_device_number_t timer_number, timer_channel_number_t channel, size_t nanoseconds);
/**
* @brief Init timer
*
* @param[in] timer timer
*/
void timer_init(timer_device_number_t timer_number);
/**
* @brief [DEPRECATED] Set timer timeout function
*
* @param[in] timer timer
* @param[in] channel channel
* @param[in] func timeout function
* @param[in] priority interrupt priority
*
*/
void timer_set_irq(timer_device_number_t timer_number, timer_channel_number_t channel, void(*func)(), uint32_t priority);
/**
* @brief Register timer interrupt user callback function
*
* @param[in] device The timer device number
* @param[in] channel The channel
* @param[in] is_one_shot Indicates if single shot
* @param[in] priority The priority
* @param[in] callback The callback function
* @param[in] ctx The context
*
* @return result
* - 0 Success
* - Other Fail
*/
int timer_irq_register(timer_device_number_t device, timer_channel_number_t channel, int is_single_shot, uint32_t priority, timer_callback_t callback, void *ctx);
/**
* @brief Deregister timer interrupt user callback function
*
* @param[in] device The timer device number
* @param[in] channel The channel
*
* @return result
* - 0 Success
* - Other Fail
*/
int timer_irq_unregister(timer_device_number_t device, timer_channel_number_t channel);
/**
* @brief Enable timer
*
* @param[in] timer timer
* @param[in] channel channel
* @param[in] enable Enable or disable
*
*/
void timer_set_enable(timer_device_number_t timer_number, timer_channel_number_t channel, uint32_t enable);
#ifdef __cplusplus
}
#endif
#endif /* __TIMER_H__ */
@@ -0,0 +1,448 @@
/* Copyright 2018 Canaan Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @file
* @brief A real-time clock (RTC) is a computer clock that keeps track of
* the current time.
*/
/**
* @file hardware_rtc.h
* @brief add from Canaan k210 SDK
* https://canaan-creative.com/developer
* @version 1.0
* @author AIIT XUOS Lab
* @date 2021-04-25
*/
#ifndef __HARDWARE_RTC_H__
#define __HARDWARE_RTC_H__
#include <platform.h>
#include <stdint.h>
#include <time.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief RTC timer mode
*
* Timer mode selector
* | Mode | Description |
* |------|------------------------|
* | 0 | Timer pause |
* | 1 | Timer time running |
* | 2 | Timer time setting |
*/
typedef enum _rtc_timer_mode_e
{
/* 0: Timer pause */
RTC_TIMER_PAUSE,
/* 1: Timer time running */
RTC_TIMER_RUNNING,
/* 2: Timer time setting */
RTC_TIMER_SETTING,
/* Max count of this enum*/
RTC_TIMER_MAX
} rtc_timer_mode_t;
/*
* @brief RTC tick interrupt mode
*
* Tick interrupt mode selector
* | Mode | Description |
* |------|------------------------|
* | 0 | Interrupt every second |
* | 1 | Interrupt every minute |
* | 2 | Interrupt every hour |
* | 3 | Interrupt every day |
*/
typedef enum _rtc_tick_interrupt_mode_e
{
/* 0: Interrupt every second */
RTC_INT_SECOND,
/* 1: Interrupt every minute */
RTC_INT_MINUTE,
/* 2: Interrupt every hour */
RTC_INT_HOUR,
/* 3: Interrupt every day */
RTC_INT_DAY,
/* Max count of this enum*/
RTC_INT_MAX
} rtc_tick_interrupt_mode_t;
/**
* @brief RTC mask structure
*
* RTC mask structure for common use
*/
typedef struct _rtc_mask
{
/* Reserved */
uint32_t resv : 1;
/* Second mask */
uint32_t second : 1;
/* Minute mask */
uint32_t minute : 1;
/* Hour mask */
uint32_t hour : 1;
/* Week mask */
uint32_t week : 1;
/* Day mask */
uint32_t day : 1;
/* Month mask */
uint32_t month : 1;
/* Year mask */
uint32_t year : 1;
} __attribute__((packed, aligned(1))) rtc_mask_t;
/**
* @brief RTC register
*
* @note RTC register table
*
* | Offset | Name | Description |
* |-----------|----------------|-------------------------------------|
* | 0x00 | date | Timer date information |
* | 0x04 | time | Timer time information |
* | 0x08 | alarm_date | Alarm date information |
* | 0x0c | alarm_time | Alarm time information |
* | 0x10 | initial_count | Timer counter initial value |
* | 0x14 | current_count | Timer counter current value |
* | 0x18 | interrupt_ctrl | RTC interrupt settings |
* | 0x1c | register_ctrl | RTC register settings |
* | 0x20 | reserved0 | Reserved |
* | 0x24 | reserved1 | Reserved |
* | 0x28 | extended | Timer extended information |
*
*/
/**
* @brief Timer date information
*
* No. 0 Register (0x00)
*/
typedef struct _rtc_date
{
/* Week. Range [0,6]. 0 is Sunday. */
uint32_t week : 3;
/* Reserved */
uint32_t resv0 : 5;
/* Day. Range [1,31] or [1,30] or [1,29] or [1,28] */
uint32_t day : 5;
/* Reserved */
uint32_t resv1 : 3;
/* Month. Range [1,12] */
uint32_t month : 4;
/* Year. Range [0,99] */
uint32_t year : 12;
} __attribute__((packed, aligned(4))) rtc_date_t;
/**
* @brief Timer time information
*
* No. 1 Register (0x04)
*/
typedef struct _rtc_time
{
/* Reserved */
uint32_t resv0 : 10;
/* Second. Range [0,59] */
uint32_t second : 6;
/* Minute. Range [0,59] */
uint32_t minute : 6;
/* Reserved */
uint32_t resv1 : 2;
/* Hour. Range [0,23] */
uint32_t hour : 5;
/* Reserved */
uint32_t resv2 : 3;
} __attribute__((packed, aligned(4))) rtc_time_t;
/**
* @brief Alarm date information
*
* No. 2 Register (0x08)
*/
typedef struct _rtc_alarm_date
{
/* Alarm Week. Range [0,6]. 0 is Sunday. */
uint32_t week : 3;
/* Reserved */
uint32_t resv0 : 5;
/* Alarm Day. Range [1,31] or [1,30] or [1,29] or [1,28] */
uint32_t day : 5;
/* Reserved */
uint32_t resv1 : 3;
/* Alarm Month. Range [1,12] */
uint32_t month : 4;
/* Alarm Year. Range [0,99] */
uint32_t year : 12;
} __attribute__((packed, aligned(4))) rtc_alarm_date_t;
/**
* @brief Alarm time information
*
* No. 3 Register (0x0c)
*/
typedef struct _rtc_alarm_time
{
/* Reserved */
uint32_t resv0 : 10;
/* Alarm Second. Range [0,59] */
uint32_t second : 6;
/* Alarm Minute. Range [0,59] */
uint32_t minute : 6;
/* Reserved */
uint32_t resv1 : 2;
/* Alarm Hour. Range [0,23] */
uint32_t hour : 5;
/* Reserved */
uint32_t resv2 : 3;
} __attribute__((packed, aligned(4))) rtc_alarm_time_t;
/**
* @brief Timer counter initial value
*
* No. 4 Register (0x10)
*/
typedef struct _rtc_initial_count
{
/* RTC counter initial value */
uint32_t count : 32;
} __attribute__((packed, aligned(4))) rtc_initial_count_t;
/**
* @brief Timer counter current value
*
* No. 5 Register (0x14)
*/
typedef struct _rtc_current_count
{
/* RTC counter current value */
uint32_t count : 32;
} __attribute__((packed, aligned(4))) rtc_current_count_t;
/**
* @brief RTC interrupt settings
*
* No. 6 Register (0x18)
*/
typedef struct _rtc_interrupt_ctrl
{
/* Reserved */
uint32_t tick_enable : 1;
/* Alarm interrupt enable */
uint32_t alarm_enable : 1;
/* Tick interrupt enable */
uint32_t tick_int_mode : 2;
/* Reserved */
uint32_t resv : 20;
/* Alarm compare mask for interrupt */
uint32_t alarm_compare_mask : 8;
} __attribute__((packed, aligned(4))) rtc_interrupt_ctrl_t;
/**
* @brief RTC register settings
*
* No. 7 Register (0x1c)
*/
typedef struct _rtc_register_ctrl
{
/* RTC timer read enable */
uint32_t read_enable : 1;
/* RTC timer write enable */
uint32_t write_enable : 1;
/* Reserved */
uint32_t resv0 : 11;
/* RTC timer mask */
uint32_t TimerMask : 8;
/* RTC alarm mask */
uint32_t alarm_mask : 8;
/* RTC counter initial count value mask */
uint32_t initial_count_mask : 1;
/* RTC interrupt register mask */
uint32_t interrupt_register_mask : 1;
/* Reserved */
uint32_t resv1 : 1;
} __attribute__((packed, aligned(4))) rtc_register_ctrl_t;
/**
* @brief Reserved
*
* No. 8 Register (0x20)
*/
typedef struct _rtc_reserved0
{
/* Reserved */
uint32_t resv : 32;
} __attribute__((packed, aligned(4))) rtc_reserved0_t;
/**
* @brief Reserved
*
* No. 9 Register (0x24)
*/
typedef struct _rtc_reserved1
{
/* Reserved */
uint32_t resv : 32;
} __attribute__((packed, aligned(4))) rtc_reserved1_t;
/**
* @brief Timer extended information
*
* No. 10 Register (0x28)
*/
typedef struct _rtc_extended
{
/* Century. Range [0,31] */
uint32_t century : 5;
/* Is leap year. 1 is leap year, 0 is not leap year */
uint32_t leap_year : 1;
/* Reserved */
uint32_t resv : 26;
} __attribute__((packed, aligned(4))) rtc_extended_t;
/**
* @brief Real-time clock struct
*
* A real-time clock (RTC) is a computer clock that keeps track of
* the current time.
*/
typedef struct _rtc
{
/* No. 0 (0x00): Timer date information */
rtc_date_t date;
/* No. 1 (0x04): Timer time information */
rtc_time_t time;
/* No. 2 (0x08): Alarm date information */
rtc_alarm_date_t alarm_date;
/* No. 3 (0x0c): Alarm time information */
rtc_alarm_time_t alarm_time;
/* No. 4 (0x10): Timer counter initial value */
rtc_initial_count_t initial_count;
/* No. 5 (0x14): Timer counter current value */
rtc_current_count_t current_count;
/* No. 6 (0x18): RTC interrupt settings */
rtc_interrupt_ctrl_t interrupt_ctrl;
/* No. 7 (0x1c): RTC register settings */
rtc_register_ctrl_t register_ctrl;
/* No. 8 (0x20): Reserved */
rtc_reserved0_t reserved0;
/* No. 9 (0x24): Reserved */
rtc_reserved1_t reserved1;
/* No. 10 (0x28): Timer extended information */
rtc_extended_t extended;
} __attribute__((packed, aligned(4))) rtc_t;
/**
* @brief Real-time clock object
*/
extern volatile rtc_t *const rtc;
extern volatile uint32_t *const rtc_base;
/**
* @brief Set date time to RTC
*
* @param[in] year The year
* @param[in] month The month
* @param[in] day The day
* @param[in] hour The hour
* @param[in] minute The minute
* @param[in] second The second
*
* @return result
* - 0 Success
* - Other Fail
*/
int rtc_timer_set(int year, int month, int day, int hour, int minute, int second);
/**
* @brief Get date time from RTC
*
* @param year The year
* @param month The month
* @param day The day
* @param hour The hour
* @param minute The minute
* @param second The second
*
* @return result
* - 0 Success
* - Other Fail
*/
int rtc_timer_get(int *year, int *month, int *day, int *hour, int *minute, int *second);
/**
* @brief Initialize RTC
*
* @return Result
* - 0 Success
* - Other Fail
*/
int rtc_init(void);
/**
* @brief Set RTC in protect mode or not
*
* @param enable Enable flag
*
* @return result
* - 0 Success
* - Other Fail
*/
int rtc_protect_set(int enable);
/**
* @brief Set RTC timer mode
*
* @param timer_mode Timer mode
*
*/
void rtc_timer_set_mode(rtc_timer_mode_t timer_mode);
/**
* @brief Set RTC timer clock frequency
*
* @param frequency Frequency
*
* @return result
* - 0 Success
* - Other Fail
*/
int rtc_timer_set_clock_frequency(unsigned int frequency);
/**
* @brief Set RTC timer clock count value
*
* @param count Count
*
* @return result
* - 0 Success
* - Other Fail
*/
int rtc_timer_set_clock_count_value(unsigned int count);
#ifdef __cplusplus
}
#endif
#endif /* _DRIVER_RTC_H */
@@ -0,0 +1,180 @@
/* Copyright 2018 Canaan Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @file wdt.h
* @brief add from Canaan k210 SDK
* https://canaan-creative.com/developer
* @version 1.0
* @author AIIT XUOS Lab
* @date 2021-04-25
*/
#ifndef __WDT_H__
#define __WDT_H__
#include <stdint.h>
#include <stddef.h>
#include <plic.h>
#ifdef __cplusplus
extern "C" {
#endif
/* clang-format off */
typedef struct _wdt
{
/* WDT Control Register (0x00) */
volatile uint32_t cr;
/* WDT Timeout Range Register (0x04) */
volatile uint32_t torr;
/* WDT Current Counter Value Register (0x08) */
volatile uint32_t ccvr;
/* WDT Counter Restart Register (0x0c) */
volatile uint32_t crr;
/* WDT Interrupt Status Register (0x10) */
volatile uint32_t stat;
/* WDT Interrupt Clear Register (0x14) */
volatile uint32_t eoi;
/* reserverd (0x18) */
volatile uint32_t resv1;
/* WDT Protection level Register (0x1c) */
volatile uint32_t prot_level;
/* reserved (0x20-0xe0) */
volatile uint32_t resv4[49];
/* WDT Component Parameters Register 5 (0xe4) */
volatile uint32_t comp_param_5;
/* WDT Component Parameters Register 4 (0xe8) */
volatile uint32_t comp_param_4;
/* WDT Component Parameters Register 3 (0xec) */
volatile uint32_t comp_param_3;
/* WDT Component Parameters Register 2 (0xf0) */
volatile uint32_t comp_param_2;
/* WDT Component Parameters Register 1 (0xf4) */
volatile uint32_t comp_param_1;
/* WDT Component Version Register (0xf8) */
volatile uint32_t comp_version;
/* WDT Component Type Register (0xfc) */
volatile uint32_t comp_type;
} __attribute__((packed, aligned(4))) wdt_t;
typedef enum _wdt_device_number
{
WDT_DEVICE_0,
WDT_DEVICE_1,
WDT_DEVICE_MAX,
} wdt_device_number_t;
#define WDT_RESET_ALL 0x00000000U
#define WDT_RESET_CPU 0x00000001U
/* WDT Control Register */
#define WDT_CR_ENABLE 0x00000001U
#define WDT_CR_RMOD_MASK 0x00000002U
#define WDT_CR_RMOD_RESET 0x00000000U
#define WDT_CR_RMOD_INTERRUPT 0x00000002U
#define WDT_CR_RPL_MASK 0x0000001CU
#define WDT_CR_RPL(x) ((x) << 2)
/* WDT Timeout Range Register */
#define WDT_TORR_TOP_MASK 0x000000FFU
#define WDT_TORR_TOP(x) ((x) << 4 | (x) << 0)
/* WDT Current Counter Value Register */
#define WDT_CCVR_MASK 0xFFFFFFFFU
/* WDT Counter Restart Register */
#define WDT_CRR_MASK 0x00000076U
/* WDT Interrupt Status Register */
#define WDT_STAT_MASK 0x00000001U
/* WDT Interrupt Clear Register */
#define WDT_EOI_MASK 0x00000001U
/* WDT Protection level Register */
#define WDT_PROT_LEVEL_MASK 0x00000007U
/* WDT Component Parameter Register 5 */
#define WDT_COMP_PARAM_5_CP_WDT_USER_TOP_MAX_MASK 0xFFFFFFFFU
/* WDT Component Parameter Register 4 */
#define WDT_COMP_PARAM_4_CP_WDT_USER_TOP_INIT_MAX_MASK 0xFFFFFFFFU
/* WDT Component Parameter Register 3 */
#define WDT_COMP_PARAM_3_CD_WDT_TOP_RST_MASK 0xFFFFFFFFU
/* WDT Component Parameter Register 2 */
#define WDT_COMP_PARAM_3_CP_WDT_CNT_RST_MASK 0xFFFFFFFFU
/* WDT Component Parameter Register 1 */
#define WDT_COMP_PARAM_1_WDT_ALWAYS_EN_MASK 0x00000001U
#define WDT_COMP_PARAM_1_WDT_DFLT_RMOD_MASK 0x00000002U
#define WDT_COMP_PARAM_1_WDT_DUAL_TOP_MASK 0x00000004U
#define WDT_COMP_PARAM_1_WDT_HC_RMOD_MASK 0x00000008U
#define WDT_COMP_PARAM_1_WDT_HC_RPL_MASK 0x00000010U
#define WDT_COMP_PARAM_1_WDT_HC_TOP_MASK 0x00000020U
#define WDT_COMP_PARAM_1_WDT_USE_FIX_TOP_MASK 0x00000040U
#define WDT_COMP_PARAM_1_WDT_PAUSE_MASK 0x00000080U
#define WDT_COMP_PARAM_1_APB_DATA_WIDTH_MASK 0x00000300U
#define WDT_COMP_PARAM_1_WDT_DFLT_RPL_MASK 0x00001C00U
#define WDT_COMP_PARAM_1_WDT_DFLT_TOP_MASK 0x000F0000U
#define WDT_COMP_PARAM_1_WDT_DFLT_TOP_INIT_MASK 0x00F00000U
#define WDT_COMP_PARAM_1_WDT_CNT_WIDTH_MASK 0x1F000000U
/* WDT Component Version Register */
#define WDT_COMP_VERSION_MASK 0xFFFFFFFFU
/* WDT Component Type Register */
#define WDT_COMP_TYPE_MASK 0xFFFFFFFFU
/* clang-format on */
/**
* @brief Feed wdt
*/
void wdt_feed(wdt_device_number_t id);
/**
* @brief Start wdt
*
* @param[in] id Wdt id 0 or 1
* @param[in] time_out_ms Wdt trigger time
* @param[in] on_irq Wdt interrupt callback
*
*/
void wdt_start(wdt_device_number_t id, uint64_t time_out_ms, plic_irq_callback_t on_irq);
/**
* @brief Start wdt
*
* @param[in] id Wdt id 0 or 1
* @param[in] time_out_ms Wdt trigger time
* @param[in] on_irq Wdt interrupt callback
* @param[in] ctx Param of callback
*
* @return Wdt time
*
*/
uint32_t wdt_init(wdt_device_number_t id, uint64_t time_out_ms, plic_irq_callback_t on_irq, void *ctx);
/**
* @brief Stop wdt
*
* @param[in] id Wdt id 0 or 1
*
*/
void wdt_stop(wdt_device_number_t id);
/**
* @brief Clear wdt interrupt
*
* @param[in] id Wdt id 0 or 1
*
*/
void wdt_clear_interrupt(wdt_device_number_t id);
#ifdef __cplusplus
}
#endif
#endif /* __WDT_H__ */
@@ -0,0 +1,11 @@
if BSP_USING_RTC
config RTC_BUS_NAME
string "rtc bus name"
default "rtc"
config RTC_DRV_NAME
string "rtc bus driver name"
default "rtc_drv"
config RTC_DEVICE_NAME
string "rtc bus device name"
default "rtc_dev"
endif
@@ -0,0 +1,3 @@
SRC_FILES := connect_rtc.c hardware_rtc.c
include $(KERNEL_ROOT)/compiler.mk
@@ -0,0 +1,183 @@
/*
* Copyright (c) 2020 AIIT XUOS Lab
* XiUOS is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
/**
* @file connect_rtc.c
* @brief support aiit-riscv64-board rtc function and register to bus framework
* @version 1.0
* @author AIIT XUOS Lab
* @date 2021-04-25
*/
#include <connect_rtc.h>
#include <hardware_rtc.h>
#include <stdint.h>
#include <stdlib.h>
#include <sysctl.h>
#include <time.h>
static int GetWeekDay(int year, int month, int day)
{
/* Magic method to get weekday */
int weekday = (day += month < 3 ? year-- : year - 2,
23 * month / 9 + day + 4 + year / 4 - year / 100 + year / 400) % 7;
return weekday;
}
static uint32 RtcConfigure(void *drv, struct BusConfigureInfo *configure_info)
{
NULL_PARAM_CHECK(drv);
struct RtcDriver *rtc_drv = (struct RtcDriver *)drv;
struct RtcDrvConfigureParam *drv_param = (struct RtcDrvConfigureParam *)configure_info->private_data;
int cmd = drv_param->rtc_operation_cmd;
time_t *time = drv_param->time;
switch (cmd)
{
case OPER_RTC_GET_TIME:
{
struct tm ct;
int year,month,day,hour,minute,second;
memset(&ct,0,sizeof(struct tm));
rtc_timer_get(&year, &month, &day, &hour, &minute, &second);
ct.tm_year = year - 1900;
ct.tm_mon = month - 1;
ct.tm_mday = day;
ct.tm_wday = GetWeekDay(year, month, day);
ct.tm_hour = hour;
ct.tm_min = minute;
ct.tm_sec = second;
*time = mktime(&ct);
}
break;
case OPER_RTC_SET_TIME:
{
struct tm *ct;
struct tm tm_new;
x_base lock;
lock = CriticalAreaLock();
ct = localtime(time);
memcpy(&tm_new, ct, sizeof(struct tm));
CriticalAreaUnLock(lock);
sysctl_reset(SYSCTL_RESET_RTC);
sysctl_clock_enable(SYSCTL_CLOCK_RTC);
rtc_protect_set(0);
rtc_timer_set_clock_frequency(SysctlClockGetFreq(SYSCTL_CLOCK_IN0));
rtc_timer_set_clock_count_value(1);
rtc_timer_set_mode(RTC_TIMER_RUNNING);
if (rtc_timer_set(tm_new.tm_year+1900,tm_new.tm_mon+1,tm_new.tm_mday,
tm_new.tm_hour,tm_new.tm_min,tm_new.tm_sec)==-1)
return ERROR;
}
break;
}
return EOK;
}
/*manage the rtc device operations*/
static const struct RtcDevDone dev_done =
{
.open = NONE,
.close = NONE,
.write = NONE,
.read = NONE,
};
static int BoardRtcBusInit(struct RtcBus *rtc_bus, struct RtcDriver *rtc_driver)
{
x_err_t ret = EOK;
/*Init the rtc bus */
ret = RtcBusInit(rtc_bus, RTC_BUS_NAME);
if (EOK != ret) {
KPrintf("HwRtcInit RtcBusInit error %d\n", ret);
return ERROR;
}
/*Init the rtc driver*/
ret = RtcDriverInit(rtc_driver, RTC_DRV_NAME);
if (EOK != ret) {
KPrintf("HwRtcInit RtcDriverInit error %d\n", ret);
return ERROR;
}
/*Attach the rtc driver to the rtc bus*/
ret = RtcDriverAttachToBus(RTC_DRV_NAME, RTC_BUS_NAME);
if (EOK != ret) {
KPrintf("HwRtcInit RtcDriverAttachToBus error %d\n", ret);
return ERROR;
}
return ret;
}
/*Attach the rtc device to the rtc bus*/
static int BoardRtcDevBend(void)
{
x_err_t ret = EOK;
static struct RtcHardwareDevice rtc_device;
memset(&rtc_device, 0, sizeof(struct RtcHardwareDevice));
rtc_device.dev_done = &(dev_done);
ret = RtcDeviceRegister(&rtc_device, NONE, RTC_DEVICE_NAME);
if (EOK != ret) {
KPrintf("HwRtcInit RtcDeviceInit device %s error %d\n", RTC_DEVICE_NAME, ret);
return ERROR;
}
ret = RtcDeviceAttachToBus(RTC_DEVICE_NAME, RTC_BUS_NAME);
if (EOK != ret) {
KPrintf("HwRtcInit RtcDeviceAttachToBus device %s error %d\n", RTC_DEVICE_NAME, ret);
return ERROR;
}
return ret;
}
int HwRtcInit(void)
{
x_err_t ret = EOK;
static struct RtcBus rtc_bus;
memset(&rtc_bus, 0, sizeof(struct RtcBus));
static struct RtcDriver rtc_driver;
memset(&rtc_driver, 0, sizeof(struct RtcDriver));
rtc_driver.configure = &(RtcConfigure);
ret = BoardRtcBusInit(&rtc_bus, &rtc_driver);
if (EOK != ret) {
KPrintf("HwRtcInit error ret %u\n", ret);
return ERROR;
}
ret = BoardRtcDevBend();
if (EOK != ret) {
KPrintf("HwRtcInit error ret %u\n", ret);
}
rtc_init();
return ret;
}
@@ -0,0 +1,597 @@
/* Copyright 2018 Canaan Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @file hardware_rtc.c
* @brief add from Canaan k210 SDK
* https://canaan-creative.com/developer
* @version 1.0
* @author AIIT XUOS Lab
* @date 2021-04-25
*/
#include <encoding.h>
#include <hardware_rtc.h>
#include <stdint.h>
#include <stdlib.h>
#include <sysctl.h>
#include <time.h>
volatile rtc_t *const rtc = (volatile rtc_t *)RTC_BASE_ADDR;
struct tm rtc_date_time;
void rtc_timer_set_mode(rtc_timer_mode_t timer_mode)
{
rtc_register_ctrl_t register_ctrl = rtc->register_ctrl;
switch (timer_mode)
{
case RTC_TIMER_PAUSE:
register_ctrl.read_enable = 0;
register_ctrl.write_enable = 0;
break;
case RTC_TIMER_RUNNING:
register_ctrl.read_enable = 1;
register_ctrl.write_enable = 0;
break;
case RTC_TIMER_SETTING:
register_ctrl.read_enable = 0;
register_ctrl.write_enable = 1;
break;
default:
register_ctrl.read_enable = 0;
register_ctrl.write_enable = 0;
break;
}
rtc->register_ctrl = register_ctrl;
}
rtc_timer_mode_t rtc_timer_get_mode(void)
{
rtc_register_ctrl_t register_ctrl = rtc->register_ctrl;
rtc_timer_mode_t timer_mode = RTC_TIMER_PAUSE;
if ((!register_ctrl.read_enable) && (!register_ctrl.write_enable))
{
/* RTC_TIMER_PAUSE */
timer_mode = RTC_TIMER_PAUSE;
}
else if ((register_ctrl.read_enable) && (!register_ctrl.write_enable))
{
/* RTC_TIMER_RUNNING */
timer_mode = RTC_TIMER_RUNNING;
}
else if ((!register_ctrl.read_enable) && (register_ctrl.write_enable)) {
/* RTC_TIMER_SETTING */
timer_mode = RTC_TIMER_SETTING;
}
else
{
/* Something is error, reset timer mode */
rtc_timer_set_mode(timer_mode);
}
return timer_mode;
}
static inline int rtc_in_range(int value, int min, int max)
{
return ((value >= min) && (value <= max));
}
int rtc_timer_set_tm(const struct tm *tm)
{
rtc_date_t timer_date;
rtc_time_t timer_time;
rtc_extended_t timer_extended;
if (tm)
{
/*
* Range of tm->tm_sec could be [0,61]
*
* Range of tm->tm_sec allows for a positive leap second. Two
* leap seconds in the same minute are not allowed (the C90
* range 0..61 was a defect)
*/
if (rtc_in_range(tm->tm_sec, 0, 59))
timer_time.second = tm->tm_sec;
else
return -1;
/* Range of tm->tm_min could be [0,59] */
if (rtc_in_range(tm->tm_min, 0, 59))
timer_time.minute = tm->tm_min;
else
return -1;
/* Range of tm->tm_hour could be [0, 23] */
if (rtc_in_range(tm->tm_hour, 0, 23))
timer_time.hour = tm->tm_hour;
else
return -1;
/* Range of tm->tm_mday could be [1, 31] */
if (rtc_in_range(tm->tm_mday, 1, 31))
timer_date.day = tm->tm_mday;
else
return -1;
/*
* Range of tm->tm_mon could be [0, 11]
* But in this RTC, date.month should be [1, 12]
*/
if (rtc_in_range(tm->tm_mon, 0, 11))
timer_date.month = tm->tm_mon + 1;
else
return -1;
/*
* Range of tm->tm_year is the years since 1900
* But in this RTC, year is split into year and century
* In this RTC, century range is [0,31], year range is [0,99]
*/
int human_year = tm->tm_year + 1900;
int rtc_year = human_year % 100;
int rtc_century = human_year / 100;
if (rtc_in_range(rtc_year, 0, 99) &&
rtc_in_range(rtc_century, 0, 31))
{
timer_date.year = rtc_year;
timer_extended.century = rtc_century;
}
else
return -1;
/* Range of tm->tm_wday could be [0, 6] */
if (rtc_in_range(tm->tm_wday, 0, 6))
timer_date.week = tm->tm_wday;
else
return -1;
/* Set RTC mode to timer setting mode */
rtc_timer_set_mode(RTC_TIMER_SETTING);
/* Write value to RTC */
rtc->date = timer_date;
rtc->time = timer_time;
rtc->extended = timer_extended;
/* Get CPU current freq */
unsigned long freq = SysctlClockGetFreq(SYSCTL_CLOCK_CPU);
/* Set threshold to 1/26000000 s */
freq = freq / 26000000;
/* Get current CPU cycle */
unsigned long start_cycle = read_cycle();
/* Wait for 1/26000000 s to sync data */
while (read_cycle() - start_cycle < freq)
continue;
/* Set RTC mode to timer running mode */
rtc_timer_set_mode(RTC_TIMER_RUNNING);
}
return 0;
}
int rtc_timer_set_alarm_tm(const struct tm *tm)
{
rtc_alarm_date_t alarm_date;
rtc_alarm_time_t alarm_time;
if (tm) {
/*
* Range of tm->tm_sec could be [0,61]
*
* Range of tm->tm_sec allows for a positive leap second. Two
* leap seconds in the same minute are not allowed (the C90
* range 0..61 was a defect)
*/
if (rtc_in_range(tm->tm_sec, 0, 59))
alarm_time.second = tm->tm_sec;
else
return -1;
/* Range of tm->tm_min could be [0,59] */
if (rtc_in_range(tm->tm_min, 0, 59))
alarm_time.minute = tm->tm_min;
else
return -1;
/* Range of tm->tm_hour could be [0, 23] */
if (rtc_in_range(tm->tm_hour, 0, 23))
alarm_time.hour = tm->tm_hour;
else
return -1;
/* Range of tm->tm_mday could be [1, 31] */
if (rtc_in_range(tm->tm_mday, 1, 31))
alarm_date.day = tm->tm_mday;
else
return -1;
/*
* Range of tm->tm_mon could be [0, 11]
* But in this RTC, date.month should be [1, 12]
*/
if (rtc_in_range(tm->tm_mon, 0, 11))
alarm_date.month = tm->tm_mon + 1;
else
return -1;
/*
* Range of tm->tm_year is the years since 1900
* But in this RTC, year is split into year and century
* In this RTC, century range is [0,31], year range is [0,99]
*/
int human_year = tm->tm_year + 1900;
int rtc_year = human_year % 100;
int rtc_century = human_year / 100;
if (rtc_in_range(rtc_year, 0, 99) &&
rtc_in_range(rtc_century, 0, 31))
{
alarm_date.year = rtc_year;
} else
return -1;
/* Range of tm->tm_wday could be [0, 6] */
if (rtc_in_range(tm->tm_wday, 0, 6))
alarm_date.week = tm->tm_wday;
else
return -1;
/* Write value to RTC */
rtc->alarm_date = alarm_date;
rtc->alarm_time = alarm_time;
}
return 0;
}
static int rtc_year_is_leap(int year)
{
return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
}
static int rtc_get_yday(int year, int month, int day)
{
static const int days[2][13] =
{
{0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334},
{0, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335}
};
int leap = rtc_year_is_leap(year);
return days[leap][month] + day;
}
static int rtc_get_wday(int year, int month, int day)
{
/* Magic method to get weekday */
int weekday = (day += month < 3 ? year-- : year - 2, 23 * month / 9 + day + 4 + year / 4 - year / 100 + year / 400) % 7;
return weekday;
}
struct tm *rtc_timer_get_tm(void)
{
if (rtc_timer_get_mode() != RTC_TIMER_RUNNING)
return NULL;
rtc_date_t timer_date = rtc->date;
rtc_time_t timer_time = rtc->time;
rtc_extended_t timer_extended = rtc->extended;
struct tm *tm = &rtc_date_time;
tm->tm_sec = timer_time.second % 60;
tm->tm_min = timer_time.minute % 60;
tm->tm_hour = timer_time.hour % 24;
tm->tm_mday = (timer_date.day - 1) % 31 + 1;
tm->tm_mon = (timer_date.month - 1)% 12;
tm->tm_year = (timer_date.year % 100) + (timer_extended.century * 100) - 1900;
tm->tm_wday = timer_date.week;
tm->tm_yday = rtc_get_yday(tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday);
tm->tm_isdst = -1;
return tm;
}
struct tm *rtc_timer_get_alarm_tm(void)
{
if (rtc_timer_get_mode() != RTC_TIMER_RUNNING)
return NULL;
rtc_alarm_date_t alarm_date = rtc->alarm_date;
rtc_alarm_time_t alarm_time = rtc->alarm_time;
rtc_extended_t timer_extended = rtc->extended;
struct tm *tm = &rtc_date_time;
tm->tm_sec = alarm_time.second % 60;
tm->tm_min = alarm_time.minute % 60;
tm->tm_hour = alarm_time.hour % 24;
tm->tm_mday = alarm_date.day % 31;
tm->tm_mon = (alarm_date.month % 12) - 1;
/* Alarm and Timer use same timer_extended.century */
tm->tm_year = (alarm_date.year % 100) + (timer_extended.century * 100) - 1900;
tm->tm_wday = alarm_date.week;
tm->tm_yday = rtc_get_yday(tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday);
tm->tm_isdst = -1;
return tm;
}
int rtc_timer_set(int year, int month, int day, int hour, int minute, int second)
{
struct tm date_time =
{
.tm_sec = second,
.tm_min = minute,
.tm_hour = hour,
.tm_mday = day,
.tm_mon = month - 1,
.tm_year = year - 1900,
.tm_wday = rtc_get_wday(year, month, day),
.tm_yday = rtc_get_yday(year, month, day),
.tm_isdst = -1,
};
return rtc_timer_set_tm(&date_time);
}
int rtc_timer_get(int *year, int *month, int *day, int *hour, int *minute, int *second)
{
struct tm *tm = rtc_timer_get_tm();
if (tm)
{
if (year)
*year = tm->tm_year + 1900;
if (month)
*month = tm->tm_mon + 1;
if (day)
*day = tm->tm_mday;
if (hour)
*hour = tm->tm_hour;
if (minute)
*minute = tm->tm_min;
if (second)
*second = tm->tm_sec;
} else
return -1;
return 0;
}
int rtc_timer_set_alarm(int year, int month, int day, int hour, int minute, int second)
{
struct tm date_time = {
.tm_sec = second,
.tm_min = minute,
.tm_hour = hour,
.tm_mday = day,
.tm_mon = month - 1,
.tm_year = year - 1900,
.tm_wday = rtc_get_wday(year, month, day),
.tm_yday = rtc_get_yday(year, month, day),
.tm_isdst = -1,
};
return rtc_timer_set_alarm_tm(&date_time);
}
int rtc_timer_get_alarm(int *year, int *month, int *day, int *hour, int *minute, int *second)
{
struct tm *tm = rtc_timer_get_alarm_tm();
if (tm) {
if (year)
*year = tm->tm_year + 1900;
if (month)
*month = tm->tm_mon + 1;
if (day)
*day = tm->tm_mday;
if (hour)
*hour = tm->tm_hour;
if (minute)
*minute = tm->tm_min;
if (second)
*second = tm->tm_sec;
} else
return -1;
return 0;
}
int rtc_timer_set_clock_frequency(unsigned int frequency)
{
rtc_initial_count_t initial_count;
initial_count.count = frequency;
rtc_timer_set_mode(RTC_TIMER_SETTING);
rtc->initial_count = initial_count;
rtc_timer_set_mode(RTC_TIMER_RUNNING);
return 0;
}
unsigned int rtc_timer_get_clock_frequency(void)
{
return rtc->initial_count.count;
}
int rtc_timer_set_clock_count_value(unsigned int count)
{
rtc_current_count_t current_count;
current_count.count = count;
rtc_timer_set_mode(RTC_TIMER_SETTING);
rtc->current_count = current_count;
rtc_timer_set_mode(RTC_TIMER_RUNNING);
return 0;
}
unsigned int rtc_timer_get_clock_count_value(void)
{
return rtc->current_count.count;
}
int rtc_tick_interrupt_set(int enable)
{
rtc_interrupt_ctrl_t interrupt_ctrl = rtc->interrupt_ctrl;
interrupt_ctrl.tick_enable = enable;
rtc_timer_set_mode(RTC_TIMER_SETTING);
rtc->interrupt_ctrl = interrupt_ctrl;
rtc_timer_set_mode(RTC_TIMER_RUNNING);
return 0;
}
int rtc_tick_interrupt_get(void)
{
rtc_interrupt_ctrl_t interrupt_ctrl = rtc->interrupt_ctrl;
return interrupt_ctrl.tick_enable;
}
int rtc_tick_interrupt_mode_set(rtc_tick_interrupt_mode_t mode)
{
rtc_interrupt_ctrl_t interrupt_ctrl = rtc->interrupt_ctrl;
interrupt_ctrl.tick_int_mode = mode;
rtc_timer_set_mode(RTC_TIMER_SETTING);
rtc->interrupt_ctrl = interrupt_ctrl;
rtc_timer_set_mode(RTC_TIMER_RUNNING);
return 0;
}
rtc_tick_interrupt_mode_t rtc_tick_interrupt_mode_get(void)
{
rtc_interrupt_ctrl_t interrupt_ctrl = rtc->interrupt_ctrl;
return interrupt_ctrl.tick_int_mode;
}
int rtc_alarm_interrupt_set(int enable)
{
rtc_interrupt_ctrl_t interrupt_ctrl = rtc->interrupt_ctrl;
interrupt_ctrl.alarm_enable = enable;
rtc->interrupt_ctrl = interrupt_ctrl;
return 0;
}
int rtc_alarm_interrupt_get(void)
{
rtc_interrupt_ctrl_t interrupt_ctrl = rtc->interrupt_ctrl;
return interrupt_ctrl.alarm_enable;
}
int rtc_alarm_interrupt_mask_set(rtc_mask_t mask)
{
rtc_interrupt_ctrl_t interrupt_ctrl = rtc->interrupt_ctrl;
interrupt_ctrl.alarm_compare_mask = *(uint8_t *)&mask;
rtc->interrupt_ctrl = interrupt_ctrl;
return 0;
}
rtc_mask_t rtc_alarm_interrupt_mask_get(void)
{
rtc_interrupt_ctrl_t interrupt_ctrl = rtc->interrupt_ctrl;
uint8_t compare_mask = interrupt_ctrl.alarm_compare_mask;
return *(rtc_mask_t *)&compare_mask;
}
int rtc_protect_set(int enable)
{
rtc_register_ctrl_t register_ctrl = rtc->register_ctrl;
rtc_mask_t mask =
{
.second = 1,
/* Second mask */
.minute = 1,
/* Minute mask */
.hour = 1,
/* Hour mask */
.week = 1,
/* Week mask */
.day = 1,
/* Day mask */
.month = 1,
/* Month mask */
.year = 1,
};
rtc_mask_t unmask =
{
.second = 0,
/* Second mask */
.minute = 0,
/* Minute mask */
.hour = 0,
/* Hour mask */
.week = 0,
/* Week mask */
.day = 0,
/* Day mask */
.month = 0,
/* Month mask */
.year = 0,
};
if (enable)
{
/* Turn RTC in protect mode, no one can write time */
register_ctrl.TimerMask = *(uint8_t *)&unmask;
register_ctrl.alarm_mask = *(uint8_t *)&unmask;
register_ctrl.initial_count_mask = 0;
register_ctrl.interrupt_register_mask = 0;
}
else
{
/* Turn RTC in unprotect mode, everyone can write time */
register_ctrl.TimerMask = *(uint8_t *)&mask;
register_ctrl.alarm_mask = *(uint8_t *)&mask;
register_ctrl.initial_count_mask = 1;
register_ctrl.interrupt_register_mask = 1;
}
rtc_timer_set_mode(RTC_TIMER_SETTING);
rtc->register_ctrl = register_ctrl;
rtc_timer_set_mode(RTC_TIMER_RUNNING);
return 0;
}
int rtc_init(void)
{
/* Reset RTC */
sysctl_reset(SYSCTL_RESET_RTC);
/* Enable RTC */
sysctl_clock_enable(SYSCTL_CLOCK_RTC);
/* Unprotect RTC */
rtc_protect_set(0);
/* Set RTC clock frequency */
rtc_timer_set_clock_frequency(
SysctlClockGetFreq(SYSCTL_CLOCK_IN0)
);
rtc_timer_set_clock_count_value(1);
/* Set RTC mode to timer running mode */
rtc_timer_set_mode(RTC_TIMER_RUNNING);
return 0;
}
@@ -0,0 +1,43 @@
if BSP_USING_SOFT_SPI
config SOFT_SPI_BUS_NAME
string "soft spi bus 1 name"
default "soft_spi1_bus1"
config SOFT_SPI_DEVICE_NAME
string "soft spi dev 1 name"
default "soft_spi1_dev1"
config SOFT_SPI_DRV_NAME
string "soft spi drv 1 name"
default "soft_spi1_drv1"
config SOFT_SPI_SCK
int "soft spi sck pin"
default 26
config SOFT_SPI_MOSI
int "soft spi mosi pin"
default 27
config SOFT_SPI_MISO
int "soft spi miso pin"
default 25
config SOFT_SPI_CS0_PIN
int "soft spi cs pin"
default 28
config SOFT_SPI_DEVICE_SLAVE_ID
int "soft spi slave id"
default 0
config SOFT_SPI_CHIP_SELECT
int "soft spi chip selected"
default 0
config SOFT_SPI_CLK_DELAY
int "clk in microsecond"
default 0
endif
@@ -0,0 +1,3 @@
SRC_FILES := connect_soft_spi.c
include $(KERNEL_ROOT)/compiler.mk
@@ -0,0 +1,295 @@
#include <xizi.h>
#include <device.h>
#include <fpioa.h>
#include <gpiohs.h>
#include "drv_io_config.h"
#include <plic.h>
#include <utils.h>
#include <connect_soft_spi.h>
#include <sleep.h>
#include <sd_spi.h>
#include <dev_spi.h>
#include <bus_spi.h>
static x_err_t softSPIinit(struct SpiDriver *spi_drv, struct BusConfigureInfo *cfg)
{
NULL_PARAM_CHECK(spi_drv);
NULL_PARAM_CHECK(cfg);
// mode CPOL = 0 CPHA = 0
gpiohs_set_drive_mode(SOFT_SPI_CS0_PIN, GPIO_DM_OUTPUT);
gpiohs_set_pin(SOFT_SPI_CS0_PIN, GPIO_PV_HIGH); // set the cs gpio high
gpiohs_set_drive_mode(SOFT_SPI_SCK, GPIO_DM_OUTPUT);
gpiohs_set_drive_mode(SOFT_SPI_MOSI, GPIO_DM_OUTPUT);
gpiohs_set_drive_mode(SOFT_SPI_MISO, GPIO_DM_INPUT);
gpiohs_set_pin(SOFT_SPI_SCK, GPIO_PV_LOW);
KPrintf("%s init done\n", SOFT_SPI_BUS_NAME);
return EOK;
}
static uint32 softSpiDrvConfigure(void *drv, struct BusConfigureInfo *configure_info)
{
NULL_PARAM_CHECK(drv);
NULL_PARAM_CHECK(configure_info);
x_err_t ret = EOK;
struct SpiDriver *spi_drv = (struct SpiDriver *)drv;
struct SpiMasterParam *spi_param;
switch (configure_info->configure_cmd)
{
case OPE_INT:
softSPIinit(spi_drv, configure_info);
break;
case OPE_CFG:
break;
default:
break;
}
return ret;
}
static void soft_spi_writebyte(struct SpiHardwareDevice *spi_dev, uint8_t data)
{
int8_t i = 0;
uint8_t temp = 0;
for (i = 0; i < 8; i++)
{
temp = ((data & 0x80) == 0x80) ? 1 : 0;
data = data << 1;
gpiohs_set_pin(SOFT_SPI_SCK, GPIO_PV_LOW);
usleep(SOFT_SPI_CLK_DELAY);
if (0 == temp)
{
gpiohs_set_pin(SOFT_SPI_MOSI, GPIO_PV_LOW);
}
else
{
gpiohs_set_pin(SOFT_SPI_MOSI, GPIO_PV_HIGH);
}
gpiohs_set_pin(SOFT_SPI_SCK, GPIO_PV_HIGH);
usleep(SOFT_SPI_CLK_DELAY);
}
gpiohs_set_pin(SOFT_SPI_SCK, GPIO_PV_LOW);
}
/* 读一个字节 */
static uint8_t soft_spi_readbyte(struct SpiHardwareDevice *spi_dev)
{
uint8_t i = 0;
uint8_t read_data = 0xFF;
for (i = 0; i < 8; i++)
{
read_data = read_data << 1;
gpiohs_set_pin(SOFT_SPI_SCK, GPIO_PV_LOW);
usleep(SOFT_SPI_CLK_DELAY);
gpiohs_set_pin(SOFT_SPI_SCK, GPIO_PV_HIGH);
usleep(SOFT_SPI_CLK_DELAY);
if (1 == gpiohs_get_pin(SOFT_SPI_MISO))
{
read_data = read_data | 0x01;
}
}
return read_data;
}
/* 读写一个字节 */
// this funcition is unverify until now!
static uint8_t soft_spi_readwritebyte(struct SpiHardwareDevice *spi_dev, uint8_t data)
{
uint8_t i = 0;
uint8_t temp = 0;
uint8_t read_data = 0xFF;
for (i = 0; i < 8; i++)
{
temp = ((data & 0x80) == 0x80) ? 1 : 0;
data = data << 1;
read_data = read_data << 1;
if (temp == 0)
{
gpiohs_set_pin(SOFT_SPI_MOSI, GPIO_PV_LOW);
}
else
{
gpiohs_set_pin(SOFT_SPI_MOSI, GPIO_PV_HIGH);
}
usleep(SOFT_SPI_CLK_DELAY);
gpiohs_set_pin(SOFT_SPI_SCK, GPIO_PV_HIGH);
usleep(SOFT_SPI_CLK_DELAY);
if (gpiohs_get_pin(SOFT_SPI_MISO) == 1)
{
read_data = read_data + 1;
}
}
return read_data;
}
static uint32 softSpiWriteData(struct SpiHardwareDevice *spi_dev, struct SpiDataStandard *spi_datacfg)
{
SpiDeviceParam *dev_param = (SpiDeviceParam *)(spi_dev->haldev.private_data);
uint8 cs_gpio_pin = dev_param->spi_slave_param->spi_cs_gpio_pin;
const uint8_t *data_buff = spi_datacfg->tx_buff;
int data_length = spi_datacfg->length;
if (NONE == spi_datacfg->tx_buff)
{
data_length = 0;
}
if (spi_datacfg->spi_chip_select)
{
gpiohs_set_pin(cs_gpio_pin, GPIO_PV_LOW);
}
for (size_t i = 0; i < data_length; i++)
{
soft_spi_writebyte(spi_dev, data_buff[i]);
}
if (spi_datacfg->spi_cs_release)
{
gpiohs_set_pin(cs_gpio_pin, GPIO_PV_HIGH);
}
spi_datacfg = spi_datacfg->next;
return EOK;
}
static uint32 softSpiReadData(struct SpiHardwareDevice *spi_dev, struct SpiDataStandard *spi_datacfg)
{
SpiDeviceParam *dev_param = (SpiDeviceParam *)(spi_dev->haldev.private_data);
uint8 cs_gpio_pin = dev_param->spi_slave_param->spi_cs_gpio_pin;
uint8_t *recv_buff = spi_datacfg->rx_buff;
int recv_length = spi_datacfg->length;
if (NONE == spi_datacfg->rx_buff)
{
recv_length = 0;
}
if (spi_datacfg->spi_chip_select)
{
gpiohs_set_pin(cs_gpio_pin, GPIO_PV_LOW);
}
for (size_t i = 0; i < recv_length; i++)
{
recv_buff[i] = soft_spi_readbyte(spi_dev);
}
if (spi_datacfg->spi_cs_release)
{
gpiohs_set_pin(cs_gpio_pin, GPIO_PV_HIGH);
}
spi_datacfg = spi_datacfg->next;
return spi_datacfg->length;
}
const struct SpiDevDone soft_spi_dev_done = {
.dev_close = NONE,
.dev_open = NONE,
.dev_read = softSpiReadData,
.dev_write = softSpiWriteData};
static int BoardSoftSpiBusInit(struct SpiBus *spi_bus, struct SpiDriver *spi_driver)
{
x_err_t ret = EOK;
/*Init the spi bus */
ret = SpiBusInit(spi_bus, SOFT_SPI_BUS_NAME);
if (EOK != ret)
{
KPrintf("Board_Spi_init SpiBusInit error %d\n", ret);
return ERROR;
}
/*Init the spi driver*/
ret = SpiDriverInit(spi_driver, SOFT_SPI_DRV_NAME);
if (EOK != ret)
{
KPrintf("Board_Spi_init SpiDriverInit error %d\n", ret);
return ERROR;
}
/*Attach the spi driver to the spi bus*/
ret = SpiDriverAttachToBus(SOFT_SPI_DRV_NAME, SOFT_SPI_BUS_NAME);
if (EOK != ret)
{
KPrintf("Board_Spi_init SpiDriverAttachToBus error %d\n", ret);
return ERROR;
}
return ret;
}
static int BoardSoftSpiDevBend(void)
{
x_err_t ret = EOK;
static struct SpiHardwareDevice spi_device0;
memset(&spi_device0, 0, sizeof(struct SpiHardwareDevice));
static struct SpiSlaveParam spi_slaveparam0;
memset(&spi_slaveparam0, 0, sizeof(struct SpiSlaveParam));
spi_slaveparam0.spi_slave_id = SOFT_SPI_DEVICE_SLAVE_ID;
spi_slaveparam0.spi_cs_gpio_pin = SOFT_SPI_CS0_PIN;
spi_slaveparam0.spi_cs_select_id = SOFT_SPI_CHIP_SELECT;
spi_device0.spi_param.spi_dma_param = NONE;
spi_device0.spi_param.spi_slave_param = &spi_slaveparam0;
spi_device0.spi_dev_done = &(soft_spi_dev_done);
ret = SpiDeviceRegister(&spi_device0, (void *)(&spi_device0.spi_param), SOFT_SPI_DEVICE_NAME);
if (EOK != ret)
{
KPrintf("Board_Spi_init SpiDeviceInit device %s error %d\n", SOFT_SPI_DEVICE_NAME, ret);
return ERROR;
}
ret = SpiDeviceAttachToBus(SOFT_SPI_DEVICE_NAME, SOFT_SPI_BUS_NAME);
if (EOK != ret)
{
KPrintf("Board_Spi_init SpiDeviceAttachToBus device %s error %d\n", SOFT_SPI_DEVICE_NAME, ret);
return ERROR;
}
return ret;
}
int HwSoftSPIInit(void)
{
x_err_t ret = EOK;
static struct SpiBus spi_bus;
memset(&spi_bus, 0, sizeof(struct SpiBus));
static struct SpiDriver spi_driver;
memset(&spi_driver, 0, sizeof(struct SpiDriver));
spi_driver.configure = &(softSpiDrvConfigure);
ret = BoardSoftSpiBusInit(&spi_bus, &spi_driver);
if (EOK != ret)
{
KPrintf("Board_Spi_Init error ret %u\n", ret);
return ERROR;
}
ret = BoardSoftSpiDevBend();
if (EOK != ret)
{
KPrintf("Board_Spi_Init error ret %u\n", ret);
return ERROR;
}
return ret;
}
@@ -100,26 +100,3 @@ if BSP_USING_SPI1
endif
endif
config BSP_USING_TP
bool "Using LCD touch "
default n
if BSP_USING_TP
config BSP_TP_SCK_PIN
int "TP SCK pin number"
default 42
config BSP_TP_NCS_PIN
int "TP NCS pin number"
default 43
config BSP_TP_MISO_PIN
int "TP MISO pin number"
default 44
config BSP_TP_IRQ_PIN
int "TP IRQ pin number"
default 45
config BSP_TP_MOSI_PIN
int "TP MOSI pin number"
default 46
endif
@@ -0,0 +1,19 @@
if BSP_USING_HWTIMER
config HWTIMER_BUS_NAME_1
string "hwtimer bus name"
default "hwtim1"
menuconfig ENABLE_TIM1
bool "enable TIM1"
default y
if ENABLE_TIM1
config HWTIMER_1_DEVICE_NAME_1
string "TIM1 dev name"
default "hwtim1_dev1"
config HWTIMER_DRIVER_NAME_1
string "TIM1 drv name"
default "hwtim1_drv"
endif
endif
@@ -0,0 +1,5 @@
SRC_FILES := hardware_hwtimer.c connect_hwtimer.c
include $(KERNEL_ROOT)/compiler.mk
@@ -0,0 +1,153 @@
/*
* Copyright (c) 2020 AIIT XUOS Lab
* XiUOS is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
/**
* @file connect_hwtimer.c
* @brief support aiit-riscv64-board hwtimer function and register to bus framework
* @version 1.0
* @author AIIT XUOS Lab
* @date 2021-04-25
*/
#include <board.h>
#include <connect_hwtimer.h>
#include <fpioa.h>
#include <plic.h>
#include <stdio.h>
#include <sysctl.h>
#include <syslog.h>
static struct HwtimerCallBackInfo *ptim2_cb_info = NULL;
int timer_callback(void *ctx)
{
if (ptim2_cb_info) {
if (ptim2_cb_info->timeout_callback) {
ptim2_cb_info->timeout_callback(ptim2_cb_info->param);
}
}
return 0;
}
uint32 HwtimerOpen(void *dev)
{
struct HwtimerHardwareDevice *hwtimer_dev = dev;
ptim2_cb_info = &hwtimer_dev->hwtimer_param.cb_info;
plic_init();
sysctl_enable_irq();
timer_init(TIMER_DEVICE_1);
size_t real_time = timer_set_interval(TIMER_DEVICE_1, TIMER_CHANNEL_1, hwtimer_dev->hwtimer_param.period_millisecond *1000);
KPrintf("timer_set_interval -- real_time : %ld\n", real_time);
timer_irq_register(TIMER_DEVICE_1, TIMER_CHANNEL_1, !hwtimer_dev->hwtimer_param.repeat, 1, timer_callback, NULL);
timer_set_enable(TIMER_DEVICE_1, TIMER_CHANNEL_1, 1);
return EOK;
}
uint32 HwtimerClose(void *dev)
{
timer_set_enable(TIMER_DEVICE_1, TIMER_CHANNEL_1, 0);
return EOK;
}
/*manage the hwtimer device operations*/
static const struct HwtimerDevDone dev_done =
{
.open = HwtimerOpen,
.close = HwtimerClose,
.write = NONE,
.read = NONE,
};
/*Init hwtimer bus*/
static int BoardHwtimerBusInit(struct HwtimerBus *hwtimer_bus, struct HwtimerDriver *hwtimer_driver)
{
x_err_t ret = EOK;
/*Init the hwtimer bus */
ret = HwtimerBusInit(hwtimer_bus, HWTIMER_BUS_NAME_1);
if (EOK != ret) {
KPrintf("board_hwtimer_init HwtimerBusInit error %d\n", ret);
return ERROR;
}
/*Init the hwtimer driver*/
hwtimer_driver->configure = NONE;
ret = HwtimerDriverInit(hwtimer_driver, HWTIMER_DRIVER_NAME_1);
if (EOK != ret) {
KPrintf("board_hwtimer_init HwtimerDriverInit error %d\n", ret);
return ERROR;
}
/*Attach the hwtimer driver to the hwtimer bus*/
ret = HwtimerDriverAttachToBus(HWTIMER_DRIVER_NAME_1, HWTIMER_BUS_NAME_1);
if (EOK != ret) {
KPrintf("board_hwtimer_init USEDriverAttachToBus error %d\n", ret);
return ERROR;
}
return ret;
}
/*Attach the hwtimer device to the hwtimer bus*/
static int BoardHwtimerDevBend(void)
{
x_err_t ret = EOK;
static struct HwtimerHardwareDevice hwtimer_device_0;
memset(&hwtimer_device_0, 0, sizeof(struct HwtimerHardwareDevice));
hwtimer_device_0.dev_done = &dev_done;
ret = HwtimerDeviceRegister(&hwtimer_device_0, NONE, HWTIMER_1_DEVICE_NAME_1);
if (EOK != ret) {
KPrintf("BoardHwtimerDevBend HwtimerDeviceRegister device %s error %d\n", HWTIMER_1_DEVICE_NAME_1, ret);
return ERROR;
}
ret = HwtimerDeviceAttachToBus(HWTIMER_1_DEVICE_NAME_1, HWTIMER_BUS_NAME_1);
if (EOK != ret) {
KPrintf("BoardHwtimerDevBend HwtimerDeviceAttachToBus device %s error %d\n", HWTIMER_1_DEVICE_NAME_1, ret);
return ERROR;
}
return ret;
}
/*K210 BOARD HWTIMER INIT*/
int HwTimerInit(void)
{
x_err_t ret = EOK;
static struct HwtimerBus hwtimer_bus;
memset(&hwtimer_bus, 0, sizeof(struct HwtimerBus));
static struct HwtimerDriver hwtimer_driver;
memset(&hwtimer_driver, 0, sizeof(struct HwtimerDriver));
ret = BoardHwtimerBusInit(&hwtimer_bus, &hwtimer_driver);
if (EOK != ret) {
KPrintf("board_hwtimer_Init error ret %u\n", ret);
return ERROR;
}
ret = BoardHwtimerDevBend();
if (EOK != ret) {
KPrintf("board_hwtimer_Init error ret %u\n", ret);
return ERROR;
}
return ret;
}
@@ -0,0 +1,407 @@
/* Copyright 2018 Canaan Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @file hardware_hwtimer.c
* @brief add from Canaan k210 SDK
* https://canaan-creative.com/developer
* @version 1.0
* @author AIIT XUOS Lab
* @date 2021-04-25
*/
#include <hardware_hwtimer.h>
#include <io.h>
#include <plic.h>
#include <stddef.h>
#include <sysctl.h>
#include <syslog.h>
#include <xs_isr.h>
#include <utils.h>
/**
* @brief Private definitions for the timer instance
*/
typedef struct timer_instance
{
timer_callback_t callback;
void *ctx;
bool single_shot;
} timer_instance_t;
typedef void(*irq_manager_callback_t)(int irq, void* arg);
volatile timer_instance_t timer_instance[TIMER_DEVICE_MAX][TIMER_CHANNEL_MAX];
volatile kendryte_timer_t *const timer[3] =
{
(volatile kendryte_timer_t *)TIMER0_BASE_ADDR,
(volatile kendryte_timer_t *)TIMER1_BASE_ADDR,
(volatile kendryte_timer_t *)TIMER2_BASE_ADDR
};
void timer_init(timer_device_number_t timer_number)
{
for(size_t i = 0; i < TIMER_CHANNEL_MAX; i++)
timer_instance[timer_number][i] = (const timer_instance_t) {
.callback = NULL,
.ctx = NULL,
.single_shot = 0,
};
sysctl_clock_enable(SYSCTL_CLOCK_TIMER0 + timer_number);
}
void timer_set_clock_div(timer_device_number_t timer_number, uint32_t div)
{
sysctl_clock_set_threshold(timer_number == 0 ? SYSCTL_THRESHOLD_TIMER0 :
timer_number == 1 ? SYSCTL_THRESHOLD_TIMER1 :
SYSCTL_THRESHOLD_TIMER2, div);
}
void timer_enable(timer_device_number_t timer_number, timer_channel_number_t channel)
{
timer[timer_number]->channel[channel].control |= TIMER_CR_ENABLE;
}
void timer_disable(timer_device_number_t timer_number, timer_channel_number_t channel)
{
timer[timer_number]->channel[channel].control &= (~TIMER_CR_ENABLE);
}
void timer_enable_pwm(timer_device_number_t timer_number, timer_channel_number_t channel)
{
timer[timer_number]->channel[channel].control |= TIMER_CR_PWM_ENABLE;
}
void timer_disable_pwm(timer_device_number_t timer_number, timer_channel_number_t channel)
{
timer[timer_number]->channel[channel].control &= (~TIMER_CR_PWM_ENABLE);
}
void timer_enable_interrupt(timer_device_number_t timer_number, timer_channel_number_t channel)
{
timer[timer_number]->channel[channel].control &= (~TIMER_CR_INTERRUPT_MASK);
}
void timer_disable_interrupt(timer_device_number_t timer_number, timer_channel_number_t channel)
{
timer[timer_number]->channel[channel].control |= TIMER_CR_INTERRUPT_MASK;
}
void timer_set_mode(timer_device_number_t timer_number, timer_channel_number_t channel, uint32_t mode)
{
timer[timer_number]->channel[channel].control &= (~TIMER_CR_MODE_MASK);
timer[timer_number]->channel[channel].control |= mode;
}
void timer_set_reload(timer_device_number_t timer_number, timer_channel_number_t channel, uint32_t count)
{
timer[timer_number]->channel[channel].load_count = count;
}
void timer_set_reload2(timer_device_number_t timer_number, timer_channel_number_t channel, uint32_t count)
{
timer[timer_number]->load_count2[channel] = count;
}
uint32_t timer_get_count(timer_device_number_t timer_number, timer_channel_number_t channel)
{
return timer[timer_number]->channel[channel].current_value;
}
uint32_t timer_get_reload(timer_device_number_t timer_number, timer_channel_number_t channel)
{
return timer[timer_number]->channel[channel].load_count;
}
uint32_t timer_get_reload2(timer_device_number_t timer_number, timer_channel_number_t channel)
{
return timer[timer_number]->load_count2[channel];
}
uint32_t timer_get_interrupt_status(timer_device_number_t timer_number)
{
return timer[timer_number]->intr_stat;
}
uint32_t timer_get_raw_interrupt_status(timer_device_number_t timer_number)
{
return timer[timer_number]->raw_intr_stat;
}
uint32_t timer_channel_get_interrupt_status(timer_device_number_t timer_number, timer_channel_number_t channel)
{
return timer[timer_number]->channel[channel].intr_stat;
}
void timer_clear_interrupt(timer_device_number_t timer_number)
{
timer[timer_number]->eoi = timer[timer_number]->eoi;
}
void timer_channel_clear_interrupt(timer_device_number_t timer_number, timer_channel_number_t channel)
{
timer[timer_number]->channel[channel].eoi = timer[timer_number]->channel[channel].eoi;
}
void timer_set_enable(timer_device_number_t timer_number, timer_channel_number_t channel, uint32_t enable)
{
if (enable)
timer[timer_number]->channel[channel].control = TIMER_CR_USER_MODE | TIMER_CR_ENABLE;
else
timer[timer_number]->channel[channel].control = TIMER_CR_INTERRUPT_MASK;
}
size_t timer_set_interval(timer_device_number_t timer_number, timer_channel_number_t channel, size_t useconds)
{
uint32_t clk_freq = SysctlClockGetFreq(SYSCTL_CLOCK_TIMER0 + timer_number);
double min_step = 1e6 / clk_freq;
size_t value = (size_t)(useconds / min_step);
configASSERT(value > 0 && value < UINT32_MAX);
timer[timer_number]->channel[channel].load_count = (uint32_t)value;
return (size_t)(min_step * value);
}
typedef void(*timer_ontick)();
timer_ontick time_irq[3][4] = { NULL };
static int timer_isr(void *parm)
{
uint32_t timer_number;
for (timer_number = 0; timer_number < 3; timer_number++)
{
if (parm == timer[timer_number])
break;
}
uint32_t channel = timer[timer_number]->intr_stat;
size_t i = 0;
for (i = 0; i < 4; i++)
{
if (channel & 1)
{
if (time_irq[timer_number][i])
(time_irq[timer_number][i])();
break;
}
channel >>= 1;
}
readl(&timer[timer_number]->eoi);
return 0;
}
void timer_set_irq(timer_device_number_t timer_number, timer_channel_number_t channel, void(*func)(), uint32_t priority)
{
time_irq[timer_number][channel] = func;
if (channel < 2)
{
plic_set_priority(IRQN_TIMER0A_INTERRUPT + timer_number * 2, priority);
plic_irq_register(IRQN_TIMER0A_INTERRUPT + timer_number * 2, timer_isr, (void *)timer[timer_number]);
plic_irq_enable(IRQN_TIMER0A_INTERRUPT + timer_number * 2);
}
else
{
plic_set_priority(IRQN_TIMER0B_INTERRUPT + timer_number * 2, priority);
plic_irq_register(IRQN_TIMER0B_INTERRUPT + timer_number * 2, timer_isr, (void *)timer[timer_number]);
plic_irq_enable(IRQN_TIMER0B_INTERRUPT + timer_number * 2);
}
}
/**
* @brief Get the timer irqn by device and channel object
*
* @note Internal function, not public
* @param device The device
* @param channel The channel
* @return plic_irq_t IRQ number
*/
static plic_irq_t get_timer_irqn_by_device_and_channel(timer_device_number_t device, timer_channel_number_t channel)
{
if (device < TIMER_DEVICE_MAX && channel < TIMER_CHANNEL_MAX) {
/*
* Select timer interrupt part
* Hierarchy of Timer interrupt to PLIC
* +---------+ +-----------+
* | 0+----+ | |
* | | +--+0A |
* | 1+----+ | |
* | TIMER0 | | |
* | 2+----+ | |
* | | +--+0B |
* | 3+----+ | |
* +---------+ | |
* | |
* +---------+ | |
* | 0+----+ | |
* | | +--+1A |
* | 1+----+ | |
* | TIMER1 | | PLIC |
* | 2+----+ | |
* | | +--+1B |
* | 3+----+ | |
* +---------+ | |
* | |
* +---------+ | |
* | 0+----+ | |
* | | +--+2A |
* | 1+----+ | |
* | TIMER2 | | |
* | 2+----+ | |
* | | +--+2B |
* | 3+----+ | |
* +---------+ +-----------+
*
*/
if (channel < 2) {
/* It is part A interrupt, offset + 0 */
return IRQN_TIMER0A_INTERRUPT + device * 2;
}
else {
/* It is part B interrupt, offset + 1 */
return IRQN_TIMER0B_INTERRUPT + device * 2;
}
}
return IRQN_NO_INTERRUPT;
}
/**
* @brief Process user callback function
*
* @note Internal function, not public
* @param device The timer device
* @param ctx The context
* @return int The callback result
*/
static int timer_interrupt_handler(timer_device_number_t device, void *ctx)
{
uint32_t channel_int_stat = timer[device]->intr_stat;
for (size_t i = 0; i < TIMER_CHANNEL_MAX; i++)
{
/* Check every bit for interrupt status */
if (channel_int_stat & 1)
{
if (timer_instance[device][i].callback) {
/* Process user callback function */
timer_instance[device][i].callback(timer_instance[device][i].ctx);
/* Check if this timer is a single shot timer */
if (timer_instance[device][i].single_shot) {
/* Single shot timer, disable it */
timer_set_enable(device, i, 0);
}
}
/* Clear timer interrupt flag for specific channel */
readl(&timer[device]->channel[i].eoi);
}
channel_int_stat >>= 1;
}
/*
* NOTE:
* Don't read timer[device]->eoi here, or you will lost some interrupt
* readl(&timer[device]->eoi);
*/
return 0;
}
/**
* @brief Callback function bus for timer interrupt
*
* @note Internal function, not public
* @param ctx The context
* @return int The callback result
*/
static void timer0_interrupt_callback(int irq, void *ctx)
{
timer_interrupt_handler(TIMER_DEVICE_0, ctx);
}
/**
* @brief Callback function bus for timer interrupt
*
* @note Internal function, not public
* @param ctx The context
* @return int The callback result
*/
static void timer1_interrupt_callback(int irq, void *ctx)
{
timer_interrupt_handler(TIMER_DEVICE_1, ctx);
}
/**
* @brief Callback function bus for timer interrupt
*
* @note Internal function, not public
* @param ctx The context
* @return int The callback result
*/
static void timer2_interrupt_callback(int irq, void *ctx)
{
timer_interrupt_handler(TIMER_DEVICE_2, ctx);
}
int timer_irq_register(timer_device_number_t device, timer_channel_number_t channel, int is_single_shot, uint32_t priority, timer_callback_t callback, void *ctx)
{
if (device < TIMER_DEVICE_MAX && channel < TIMER_CHANNEL_MAX) {
plic_irq_t irq_number = get_timer_irqn_by_device_and_channel(device, channel);
irq_manager_callback_t plic_irq_callback[TIMER_DEVICE_MAX] = {
timer0_interrupt_callback,
timer1_interrupt_callback,
timer2_interrupt_callback,
};
timer_instance[device][channel] = (const timer_instance_t) {
.callback = callback,
.ctx = ctx,
.single_shot = is_single_shot,
};
// plic_set_priority(irq_number, priority);
// plic_irq_register(irq_number, plic_irq_callback[device], (void *)&timer_instance[device]);
// plic_irq_enable(irq_number);
isrManager.done->registerIrq(irq_number, plic_irq_callback[device], NULL);
isrManager.done->enableIrq(irq_number);
return 0;
}
return -1;
}
int timer_irq_unregister(timer_device_number_t device, timer_channel_number_t channel)
{
if (device < TIMER_DEVICE_MAX && channel < TIMER_CHANNEL_MAX) {
timer_instance[device][channel] = (const timer_instance_t) {
.callback = NULL,
.ctx = NULL,
.single_shot = 0,
};
/* Combine 0 and 1 to A interrupt, 2 and 3 to B interrupt */
if ((!(timer_instance[device][TIMER_CHANNEL_0].callback ||
timer_instance[device][TIMER_CHANNEL_1].callback)) ||
(!(timer_instance[device][TIMER_CHANNEL_2].callback ||
timer_instance[device][TIMER_CHANNEL_3].callback))) {
plic_irq_t irq_number = get_timer_irqn_by_device_and_channel(device, channel);
plic_irq_unregister(irq_number);
}
return 0;
}
return -1;
}
@@ -10,8 +10,8 @@ if BSP_USING_TOUCH
default "touch_dev"
config BSP_TOUCH_TP_INT
int "touch int pin"
default 36
default 30
config FPIOA_TOUCH_TP_INT
int "fpioa touch int pin"
default 12
default 30
endif
@@ -24,21 +24,33 @@
#include <bus.h>
#include <gpiohs.h>
#include <fpioa.h>
#include "gsl2038firmware.h"
struct Finger {
uint8_t fingerID;
uint32_t x;
uint32_t y;
};
struct Touch_event {
uint8_t NBfingers;
struct Finger fingers[5];
};
// #define LCD_HEIGHT BSP_LCD_X_MAX
// #define LCD_WIDTH BSP_LCD_Y_MAX
#define DEFAULT_NUM 0x0D
#define TOUCH_ADDRESS 0x44
volatile bool SemReleaseFlag = 0;
static struct Bus* i2c_bus = NONE;
static struct Bus* pin_bus = NONE;
int touch_sem = 0;
POINT Pre_Touch_Point;
#define DATA_REG 0x80
#define STATUS_REG 0xE0
/* HERE WE IMPLEMENT I2C READING AND WRITING FROM SENSOR */
/* write sensor register data */
static x_err_t WriteReg(struct HardwareDev* dev, uint8 len, uint8* buf)
static x_err_t WriteReg(struct HardwareDev* dev, char* buf, int len)
{
struct BusBlockWriteParam write_param;
write_param.pos = 0;
@@ -62,150 +74,10 @@ static x_err_t ReadRegs(struct HardwareDev* dev, uint8 len, uint8* buf)
return BusDevReadData(dev, &read_param);
}
/**
* i2c_transfer - execute a single I2C message
* @msgs: One or more messages to execute before STOP is issued to
* terminate the operation; each message begins with a START.
*/
int I2C_Transfer(struct i2c_msg* msg)
{
int16 ret = 0;
if (msg->flags & I2C_M_RD) //根据flag判断是读数据还是写数据
{
ret = ReadRegs(i2c_bus->owner_haldev, msg->len, msg->buf); //IIC读取数据
}
else
{
ret = WriteReg(i2c_bus->owner_haldev, msg->len, msg->buf); //IIC写入数据
} //正常完成的传输结构个数
return ret;
}
static int32_t GtpI2cWrite(uint8_t* buf, int32_t len)
{
struct i2c_msg msg;
int32_t ret = -1;
int32_t retries = 0;
msg.flags = !I2C_M_RD;
msg.len = len;
msg.buf = buf;
//msg.scl_rate = 300 * 1000; // for Rockchip, etc
while (retries < 5)
{
ret = I2C_Transfer(&msg);
if (ret == 1) { break; }
retries++;
}
if (retries >= 5)
{
KPrintf("I2C Write: 0x%04X, %d bytes failed, errcode: %d! Process reset.", (((uint16_t)(buf[0] << 8)) | buf[1]), len - 2, ret);
ret = -1;
}
return ret;
}
static int32_t GtpI2cRead(uint8_t* buf, int32_t len)
{
struct i2c_msg msgs[2];
int32_t ret = -1;
int32_t retries = 0;
// write reading addr.
msgs[0].flags = !I2C_M_RD;
msgs[0].len = GTP_ADDR_LENGTH;
msgs[0].buf = buf;
// read data at addr sended.
msgs[1].flags = I2C_M_RD;
msgs[1].len = len - GTP_ADDR_LENGTH;
msgs[1].buf = &buf[GTP_ADDR_LENGTH];
while (retries < 5)
{
ret = I2C_Transfer(&msgs[0]);
ret += I2C_Transfer(&msgs[1]);
if (ret == 2)break;
retries++;
}
if (retries >= 5)
{
KPrintf("I2C Read: 0x%04X, %d bytes %d times failed, errcode: %d! Process reset.\n", (((uint16_t)(buf[0] << 8)) | buf[1]), len - 2, retries, ret);
ret = -1;
}
return ret;
}
/* HERE WE IMPLEMENT TOUCH INIT */
int32_t GtpReadVersion(void)
{
int32_t ret = -1;
uint8_t buf[8] = { GTP_REG_VERSION >> 8, GTP_REG_VERSION & 0xff };
ret = GtpI2cRead(buf, sizeof(buf));
if (ret < 0)
{
KPrintf("GTP read version failed.\n");
return ret;
}
if (buf[5] == 0x00)
{
KPrintf("IC1 Version: %c%c%c_%02x%02x\n", buf[2], buf[3], buf[4], buf[7], buf[6]);
}
else
{
KPrintf("IC2 Version: %c%c%c%c_%02x%02x\n", buf[2], buf[3], buf[4], buf[5], buf[7], buf[6]);
}
return ret;
}
static int32_t GtpGetInfo(void)
{
uint8_t end_cmd[3] = { GTP_READ_COOR_ADDR >> 8, GTP_READ_COOR_ADDR & 0xFF, 0 };
uint8_t opr_buf[6] = { 0 };
int32_t ret = 0;
uint16_t abs_x_max = GTP_MAX_WIDTH;
uint16_t abs_y_max = GTP_MAX_HEIGHT;
uint8_t int_trigger_type = GTP_INT_TRIGGER;
opr_buf[0] = (uint8_t)((GTP_REG_CONFIG_DATA + 1) >> 8);
opr_buf[1] = (uint8_t)((GTP_REG_CONFIG_DATA + 1) & 0xFF);
if (GtpI2cRead(opr_buf, 6) < 0)
{
return -1;
}
abs_x_max = (opr_buf[3] << 8) + opr_buf[2];
abs_y_max = (opr_buf[5] << 8) + opr_buf[4];
opr_buf[0] = (uint8_t)((GTP_REG_CONFIG_DATA + 6) >> 8);
opr_buf[1] = (uint8_t)((GTP_REG_CONFIG_DATA + 6) & 0xFF);
if (GtpI2cRead(opr_buf, 3) < 0)
{
return 0;
}
int_trigger_type = opr_buf[2] & 0x03;
KPrintf("X_MAX = %d, Y_MAX = %d, TRIGGER = 0x%02x\n",
abs_x_max, abs_y_max, int_trigger_type);
if (GtpI2cWrite(end_cmd, 3) < 0)
{
KPrintf("I2C write end_cmd error!\n");
ret = 0;
}
return 0; ;
}
// not used in polling mode
static void GT9xx_PEN_IRQHandler(void* arg)
static void touch_pin_irqhandler(void* arg)
{
KPrintf("int hdr working.\n");
// KPrintf("int hdr working.\n");
if (!SemReleaseFlag)
{
KSemaphoreAbandon(touch_sem);
@@ -213,20 +85,20 @@ static void GT9xx_PEN_IRQHandler(void* arg)
}
}
int32_t GT9xx_INT_INIT() {
int32_t touch_irq_init()
{
int32_t ret = -ERROR;
pin_bus = PinBusInitGet();
struct PinParam pin_param;
struct BusConfigureInfo pin_configure_info;
pin_bus = PinBusInitGet();
pin_configure_info.configure_cmd = OPE_CFG;
pin_configure_info.private_data = (void*)&pin_param;
pin_param.cmd = GPIO_CONFIG_MODE;
pin_param.pin = BSP_TOUCH_TP_INT;
pin_param.mode = GPIO_CFG_INPUT_PULLUP;
pin_param.mode = GPIO_CFG_INPUT;
ret = BusDrvConfigure(pin_bus->owner_driver, &pin_configure_info);
if (ret != EOK) {
KPrintf("config pin_param %d input failed!\n", pin_param.pin);
@@ -235,8 +107,8 @@ int32_t GT9xx_INT_INIT() {
pin_param.cmd = GPIO_IRQ_REGISTER;
pin_param.pin = BSP_TOUCH_TP_INT;
pin_param.irq_set.irq_mode = GPIO_IRQ_EDGE_FALLING;
pin_param.irq_set.hdr = GT9xx_PEN_IRQHandler;
pin_param.irq_set.irq_mode = GPIO_IRQ_EDGE_BOTH;
pin_param.irq_set.hdr = touch_pin_irqhandler;
pin_param.irq_set.args = NONE;
ret = BusDrvConfigure(pin_bus->owner_driver, &pin_configure_info);
if (ret != EOK) {
@@ -264,7 +136,7 @@ int32_t GT9xx_INT_INIT() {
return EOK;
}
int32_t I2C_Touch_Init() {
int32_t I2cTouchInit() {
// using static bus information
int32_t ret = -1;
/* find I2C device and get I2C handle */
@@ -294,116 +166,68 @@ int32_t I2C_Touch_Init() {
// memset(&i2c_configure_info, 0, sizeof(struct BusConfigureInfo));
i2c_configure_info.configure_cmd = OPE_INT;
uint16 i2c_address = GTP_ADDRESS >> 1;
uint16 i2c_address = TOUCH_ADDRESS;
i2c_configure_info.private_data = (void*)&i2c_address;
BusDrvConfigure(i2c_bus->owner_driver, &i2c_configure_info);
// 3. init interruption
return GT9xx_INT_INIT();
return touch_irq_init();
}
/* HERE WE IMPLEMENT GET COORDINATE FUNCTION */
/**
* @brief 触屏处理函数,轮询或者在触摸中断调用
* @param 无
* @retval 无
*/
bool GetTouchEvent(POINT* touch_point, touch_event_t* touch_event)
void loadfw(struct HardwareDev *dev)
{
uint8_t addr;
uint8_t Wrbuf[5];
size_t source_len = sizeof(GSL2038_FW) / sizeof(struct fw_data);
for (size_t source_line = 0; source_line < source_len; source_line++) {
// addr = GSL2038_FW[source_line].offset;
memset(Wrbuf, 0 , 5);
Wrbuf[0] = GSL2038_FW[source_line].offset;
Wrbuf[1] = (char)(GSL2038_FW[source_line].val & 0x000000ff);
Wrbuf[2] = (char)((GSL2038_FW[source_line].val & 0x0000ff00) >> 8);
Wrbuf[3] = (char)((GSL2038_FW[source_line].val & 0x00ff0000) >> 16);
Wrbuf[4] = (char)((GSL2038_FW[source_line].val & 0xff000000) >> 24);
uint8_t end_cmd[3] = { GTP_READ_COOR_ADDR >> 8, GTP_READ_COOR_ADDR & 0xFF, 0 };
uint8_t point_data[2 + 1 + 8 * GTP_MAX_TOUCH + 1] = { GTP_READ_COOR_ADDR >> 8, GTP_READ_COOR_ADDR & 0xFF };
uint8_t touch_num = 0;
uint8_t finger = 0;
static uint16_t pre_touch = 0;
uint8_t* coor_data = NULL;
int32_t input_x = 0;
int32_t input_y = 0;
int32_t input_w = 0;
int32_t ret = -1;
ret = GtpI2cRead(point_data, 12);//10字节寄存器加2字节地址
if (ret < 0)
{
KPrintf("I2C transfer error. errno:%d\n ", ret);
return 0;
WriteReg(dev, Wrbuf,5);
}
}
finger = point_data[GTP_ADDR_LENGTH];//状态寄存器数据
void reset()
{
uint8_t REG[6] = {STATUS_REG, 0xE4, 0xbc, 0xbd, 0xbe, 0xbf};
uint8_t DATA[6] = {0x88, 0x04, 0x00, 0x00, 0x00, 0x00};
char reg_data[2];
if (finger == 0x00) //没有数据,退出
int i;
for (i = 0; i < sizeof(REG); ++i)
{
ret = 0;
goto exit_work_func;
// WriteReg(i2c_bus->owner_haldev, &REG[i],1);
// WriteReg(i2c_bus->owner_haldev, &DATA[i],1);
reg_data[0] = REG[i];
reg_data[1] = DATA[i];
WriteReg(i2c_bus->owner_haldev, reg_data,2);
MdelayKTask(10);
}
}
if ((finger & 0x80) == 0)//判断buffer status位
{
ret = 0;
goto exit_work_func;//坐标未就绪,数据无效
}
void startchip()
{
char reg_data[] = {0xE0, 0x00};
touch_num = finger & 0x0f;//坐标点数
if (touch_num > GTP_MAX_TOUCH)
{
ret = 0;
goto exit_work_func;//大于最大支持点数,错误退出
}
if (touch_num)
{
coor_data = &point_data[0 * 8 + 3];
input_x = coor_data[1] | (coor_data[2] << 8); //x坐标
input_y = coor_data[3] | (coor_data[4] << 8); //y坐标
input_w = coor_data[5] | (coor_data[6] << 8); //size
touch_point->X = input_x;
touch_point->Y = input_y;
*touch_event = kTouch_Down;
Pre_Touch_Point = *touch_point;
}
else if (pre_touch) //touch_ num=0 且pre_touch=0
{
*touch_point = Pre_Touch_Point;
*touch_event = kTouch_Up;
Pre_Touch_Point.X = -1;
Pre_Touch_Point.Y = -1;
}
pre_touch = touch_num;
exit_work_func:
{
ret = GtpI2cWrite(end_cmd, 3);
if (ret < 0)
{
KPrintf("I2C write end_cmd error!\n");
ret = 0;
}
}
return ret;
WriteReg(i2c_bus->owner_haldev, reg_data,2); // Registre
}
static uint32 TouchOpen(void* dev)
{
int32_t ret = -1;
int32_t ret = 0;
I2C_Touch_Init();
ret = GtpReadVersion();
if (ret < 0)
{
KPrintf("gtp read version error\n");
return ret;
}
I2cTouchInit();
ret = GtpGetInfo();
if (ret < 0)
{
KPrintf("gtp read info error\n");
return ret;
}
reset();
loadfw(i2c_bus->owner_haldev);
reset();
startchip();
touch_sem = KSemaphoreCreate(0);
if (touch_sem < 0) {
@@ -415,8 +239,32 @@ static uint32 TouchOpen(void* dev)
}
static uint32 TouchClose(void* dev)
{
{
int32_t ret = -ERROR;
struct PinParam pin_param;
struct BusConfigureInfo pin_configure_info;
pin_configure_info.configure_cmd = OPE_CFG;
pin_configure_info.private_data = (void*)&pin_param;
pin_param.cmd = GPIO_IRQ_DISABLE;
pin_param.pin = BSP_TOUCH_TP_INT;
ret = BusDrvConfigure(pin_bus->owner_driver, &pin_configure_info);
if (ret != EOK) {
KPrintf("disable pin_param %d irq failed!\n", pin_param.pin);
return -ERROR;
}
pin_param.cmd = GPIO_IRQ_FREE;
pin_param.pin = BSP_TOUCH_TP_INT;
ret = BusDrvConfigure(pin_bus->owner_driver, &pin_configure_info);
if (ret != EOK) {
KPrintf("register pin_param %d irq failed!\n", pin_param.pin);
return -ERROR;
}
KSemaphoreDelete(touch_sem);
return 0;
}
@@ -424,23 +272,35 @@ static uint32 TouchRead(void* dev, struct BusBlockReadParam* read_param)
{
uint32 ret = -1;
x_err_t result;
POINT touch_point;
touch_point.X = -1;
touch_point.Y = -1;
touch_event_t touch_event;
uint8_t TOUCHRECDATA[24] = {0};
struct Touch_event ts_event;
char status_reg = 0x80;
struct TouchDataStandard* data = (struct TouchDataStandard*)read_param->buffer;
read_param->read_length = 0;
result = KSemaphoreObtain(touch_sem, 100);
if (GetTouchEvent(&touch_point, &touch_event))
{
data->x = touch_point.X;
data->y = touch_point.Y;
result = KSemaphoreObtain(touch_sem, 1000);
// if (EOK == result)
// {
memset(TOUCHRECDATA, 0, 24);
memset(&ts_event, 0, sizeof(struct Touch_event));
read_param->read_length = read_param->size;
ret = EOK;
}
SemReleaseFlag = 0;
WriteReg(i2c_bus->owner_haldev, &status_reg, 1);
ReadRegs(i2c_bus->owner_haldev, 24, TOUCHRECDATA);
ts_event.NBfingers = TOUCHRECDATA[0];
for (int i = 0; i < ts_event.NBfingers; i++)
{
ts_event.fingers[i].x = ((((uint32_t)TOUCHRECDATA[(i * 4) + 5]) << 8) | (uint32_t)TOUCHRECDATA[(i * 4) + 4]) & 0x00000FFF; // 12 bits of X coord
ts_event.fingers[i].y = ((((uint32_t)TOUCHRECDATA[(i * 4) + 7]) << 8) | (uint32_t)TOUCHRECDATA[(i * 4) + 6]) & 0x00000FFF;
ts_event.fingers[i].fingerID = (uint32_t)TOUCHRECDATA[(i * 4) + 7] >> 4; // finger that did the touch
printf("fingers[%d] x %d y %d id %d\n",i,ts_event.fingers[i].x,ts_event.fingers[i].y,ts_event.fingers[i].fingerID);
}
data->x = ts_event.fingers[ts_event.NBfingers - 1].x;
data->y = ts_event.fingers[ts_event.NBfingers - 1].y;
SemReleaseFlag = 0;
// }
return ret;
}
@@ -0,0 +1,34 @@
menuconfig BSP_USING_WDT0
bool "Using watchdog 0 "
default n
if BSP_USING_WDT0
config WDT_BUS_NAME_0
string "watchdog bus 0 name"
default "wdt0"
config WDT_DRIVER_NAME_0
string "watchdog driver 0 name"
default "wdt0_drv"
config WDT_0_DEVICE_NAME_0
string "watchdog device 0 name"
default "wdt0_dev0"
endif
menuconfig BSP_USING_WDT1
bool "Using watchdog 1 "
default n
if BSP_USING_WDT1
config WDT_BUS_NAME_1
string "watchdog bus 1 name"
default "wdt1"
config WDT_DRIVER_NAME_1
string "watchdog driver 1 name"
default "wdt1_drv"
config WDT_1_DEVICE_NAME_1
string "watchdog device 1 name"
default "wdt1_dev1"
endif
@@ -0,0 +1,6 @@
SRC_FILES := wdt.c connect_wdt.c
include $(KERNEL_ROOT)/compiler.mk
@@ -0,0 +1,176 @@
/*
* Copyright (c) 2020 AIIT XUOS Lab
* XiUOS is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
/**
* @file connect_wdt.c
* @brief support aiit-riscv64-board watchdog function and register to bus framework
* @version 1.0
* @author AIIT XUOS Lab
* @date 2021-04-25
*/
#include <connect_wdt.h>
#include <wdt.h>
static uint32 WdtOpen(void *dev)
{
NULL_PARAM_CHECK(dev);
wdt_device_number_t id;
struct WdtHardwareDevice *wdt = (struct WdtHardwareDevice *)dev;
id = *(wdt_device_number_t *)wdt->private_data;
wdt_init(id, 4095, NONE, NONE);
return EOK;
}
static uint32 WdtConfigure(void *drv, struct BusConfigureInfo *args)
{
NULL_PARAM_CHECK(drv);
NULL_PARAM_CHECK(args);
struct WdtDriver *wdt = (struct WdtDriver *)drv;
wdt_device_number_t id = *(wdt_device_number_t *)wdt->private_data;
switch (args->configure_cmd)
{
case OPER_WDT_SET_TIMEOUT:
if (wdt_init(id, (uint64_t)*(int *)args->private_data, NONE, NONE) == 0) {
return ERROR;
}
break;
case OPER_WDT_KEEPALIVE:
wdt_feed(id);
break;
default:
return ERROR;
}
return EOK;
}
static const struct WdtDevDone dev_done =
{
WdtOpen,
NONE,
NONE,
NONE,
};
/**
* @description: Watchdog function
* @return success: EOK, failure: other
*/
int StartWatchdog(void)
{
//add feed watchdog task function
return EOK;
}
int HwWdtInit(void)
{
wdt_device_number_t id;
x_err_t ret = EOK;
#ifdef BSP_USING_WDT0
{
static struct WdtBus wdt0;
ret = WdtBusInit(&wdt0, WDT_BUS_NAME_0);
if (ret != EOK) {
KPrintf("Watchdog bus init error %d\n", ret);
return ERROR;
}
static struct WdtDriver drv0;
drv0.configure = WdtConfigure;
id = WDT_DEVICE_0;
drv0.private_data = &id;
ret = WdtDriverInit(&drv0, WDT_DRIVER_NAME_0);
if (ret != EOK) {
KPrintf("Watchdog driver init error %d\n", ret);
return ERROR;
}
ret = WdtDriverAttachToBus(WDT_DRIVER_NAME_0, WDT_BUS_NAME_0);
if (ret != EOK) {
KPrintf("Watchdog driver attach error %d\n", ret);
return ERROR;
}
static struct WdtHardwareDevice dev0;
dev0.dev_done = &dev_done;
dev0.private_data = &id;
ret = WdtDeviceRegister(&dev0, WDT_0_DEVICE_NAME_0);
if (ret != EOK) {
KPrintf("Watchdog device register error %d\n", ret);
return ERROR;
}
ret = WdtDeviceAttachToBus(WDT_0_DEVICE_NAME_0, WDT_BUS_NAME_0);
if (ret != EOK) {
KPrintf("Watchdog device register error %d\n", ret);
return ERROR;
}
}
#endif
#ifdef BSP_USING_WDT1
{
static struct WdtBus wdt1;
ret = WdtBusInit(&wdt1, WDT_BUS_NAME_1);
if (ret != EOK) {
KPrintf("Watchdog bus init error %d\n", ret);
return ERROR;
}
static struct WdtDriver drv1;
drv1.configure = WdtConfigure;
id = WDT_DEVICE_1;
drv1.private_data = &id;
ret = WdtDriverInit(&drv1, WDT_DRIVER_NAME_1);
if (ret != EOK) {
KPrintf("Watchdog driver init error %d\n", ret);
return ERROR;
}
ret = WdtDriverAttachToBus(WDT_DRIVER_NAME_1, WDT_BUS_NAME_1);
if (ret != EOK) {
KPrintf("Watchdog driver attach error %d\n", ret);
return ERROR;
}
static struct WdtHardwareDevice dev1;
dev1.dev_done = &dev_done;
dev1.private_data = &id;
ret = WdtDeviceRegister(&dev1, WDT_1_DEVICE_NAME_1);
if (ret != EOK) {
KPrintf("Watchdog device register error %d\n", ret);
return ERROR;
}
ret = WdtDeviceAttachToBus(WDT_1_DEVICE_NAME_1, WDT_BUS_NAME_1);
if (ret != EOK) {
KPrintf("Watchdog device register error %d\n", ret);
return ERROR;
}
}
#endif
return ret;
}
@@ -0,0 +1,125 @@
/* Copyright 2018 Canaan Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @file wdt.c
* @brief add from Canaan k210 SDK
* https://canaan-creative.com/developer
* @version 1.0
* @author AIIT XUOS Lab
* @date 2021-04-25
*/
#include <math.h>
#include <platform.h>
#include <plic.h>
#include <stddef.h>
#include <sysctl.h>
#include <utils.h>
#include <wdt.h>
volatile wdt_t *const wdt[2] =
{
(volatile wdt_t *)WDT0_BASE_ADDR,
(volatile wdt_t *)WDT1_BASE_ADDR
};
static void wdt_enable(wdt_device_number_t id)
{
wdt[id]->crr = WDT_CRR_MASK;
wdt[id]->cr |= WDT_CR_ENABLE;
}
static void wdt_disable(wdt_device_number_t id)
{
wdt[id]->crr = WDT_CRR_MASK;
wdt[id]->cr &= (~WDT_CR_ENABLE);
}
static void wdt_set_timeout(wdt_device_number_t id, uint8_t timeout)
{
wdt[id]->torr = WDT_TORR_TOP(timeout);
}
static void wdt_response_mode(wdt_device_number_t id, uint8_t mode)
{
wdt[id]->cr &= (~WDT_CR_RMOD_MASK);
wdt[id]->cr |= mode;
}
static uint64_t wdt_get_pclk(wdt_device_number_t id)
{
return id ? SysctlClockGetFreq(SYSCTL_CLOCK_WDT1) : SysctlClockGetFreq(SYSCTL_CLOCK_WDT0);
}
static uint8_t wdt_get_top(wdt_device_number_t id, uint64_t timeout_ms)
{
uint64_t wdt_clk = wdt_get_pclk(id);
uint64_t ret = (timeout_ms * wdt_clk / 1000) >> 16;
if (ret)
ret = (uint32_t)log2(ret);
if (ret > 0xf)
ret = 0xf;
return (uint8_t)ret;
}
void wdt_feed(wdt_device_number_t id)
{
wdt[id]->crr = WDT_CRR_MASK;
}
void wdt_clear_interrupt(wdt_device_number_t id)
{
wdt[id]->eoi = wdt[id]->eoi;
}
void wdt_start(wdt_device_number_t id, uint64_t time_out_ms, plic_irq_callback_t on_irq)
{
sysctl_reset(id ? SYSCTL_RESET_WDT1 : SYSCTL_RESET_WDT0);
sysctl_clock_set_threshold(id ? SYSCTL_THRESHOLD_WDT1 : SYSCTL_THRESHOLD_WDT0, 0);
sysctl_clock_enable(id ? SYSCTL_CLOCK_WDT1 : SYSCTL_CLOCK_WDT0);
plic_set_priority(id ? IRQN_WDT1_INTERRUPT : IRQN_WDT0_INTERRUPT, 1);
plic_irq_enable(id ? IRQN_WDT1_INTERRUPT : IRQN_WDT0_INTERRUPT);
plic_irq_register(id ? IRQN_WDT1_INTERRUPT : IRQN_WDT0_INTERRUPT, on_irq, NULL);
wdt_response_mode(id, WDT_CR_RMOD_INTERRUPT);
uint8_t m_top = wdt_get_top(id, time_out_ms);
wdt_set_timeout(id, m_top);
wdt_enable(id);
}
uint32_t wdt_init(wdt_device_number_t id, uint64_t time_out_ms, plic_irq_callback_t on_irq, void *ctx)
{
sysctl_reset(id ? SYSCTL_RESET_WDT1 : SYSCTL_RESET_WDT0);
sysctl_clock_set_threshold(id ? SYSCTL_THRESHOLD_WDT1 : SYSCTL_THRESHOLD_WDT0, 0);
sysctl_clock_enable(id ? SYSCTL_CLOCK_WDT1 : SYSCTL_CLOCK_WDT0);
plic_set_priority(id ? IRQN_WDT1_INTERRUPT : IRQN_WDT0_INTERRUPT, 1);
plic_irq_enable(id ? IRQN_WDT1_INTERRUPT : IRQN_WDT0_INTERRUPT);
plic_irq_register(id ? IRQN_WDT1_INTERRUPT : IRQN_WDT0_INTERRUPT, on_irq, ctx);
wdt_response_mode(id, WDT_CR_RMOD_INTERRUPT);
uint8_t m_top = wdt_get_top(id, time_out_ms);
wdt_set_timeout(id, m_top);
wdt_enable(id);
return (1UL << (m_top + 16 + 1)) * 1000UL / wdt_get_pclk(id);
}
void wdt_stop(wdt_device_number_t id)
{
wdt_disable(id);
}
@@ -28,6 +28,12 @@ menu "hc32f4a0 feature"
endmenu
endmenu
config MOUNT_SDCARD
bool
default n
config MOUNT_USB
bool
default n
endmenu
menu "Hardware feature"
+54 -22
View File
@@ -34,6 +34,18 @@ Modification:
#include <hc32_ll.h>
#include <connect_usart.h>
#ifdef BSP_USING_SDIO
#include <connect_sdio.h>
#endif
#ifdef BSP_USING_SPI
#include <connect_spi.h>
#endif
#ifdef BSP_USING_USB
#include <connect_usb.h>
#endif
extern void entry(void);
extern int HwUsartInit();
@@ -46,15 +58,10 @@ void SystemClockConfig(void)
stc_clock_xtal_init_t stcXtalInit;
stc_clock_pll_init_t stcPLLHInit;
/* PCLK0, HCLK Max 240MHz */
/* PCLK1, PCLK4 Max 120MHz */
/* PCLK2, PCLK3 Max 60MHz */
/* EX BUS Max 120MHz */
CLK_SetClockDiv(CLK_BUS_CLK_ALL, \
(CLK_PCLK0_DIV1 | CLK_PCLK1_DIV2 | CLK_PCLK2_DIV4 | \
CLK_PCLK3_DIV4 | CLK_PCLK4_DIV2 | CLK_EXCLK_DIV2 | \
CLK_SetClockDiv(CLK_BUS_CLK_ALL,
(CLK_PCLK0_DIV1 | CLK_PCLK1_DIV2 | CLK_PCLK2_DIV4 |
CLK_PCLK3_DIV4 | CLK_PCLK4_DIV2 | CLK_EXCLK_DIV2 |
CLK_HCLK_DIV1));
(void)CLK_XtalStructInit(&stcXtalInit);
/* Config Xtal and enable Xtal */
stcXtalInit.u8Mode = CLK_XTAL_MD_OSC;
@@ -64,26 +71,37 @@ void SystemClockConfig(void)
(void)CLK_XtalInit(&stcXtalInit);
(void)CLK_PLLStructInit(&stcPLLHInit);
stcPLLHInit.u8PLLState = CLK_PLL_ON;
stcPLLHInit.PLLCFGR = 0UL;
stcPLLHInit.PLLCFGR_f.PLLM = 1UL - 1UL;
#ifdef BSP_USING_USB
/* VCO = (8/1)*120 = 960MHz*/
stcPLLHInit.u8PLLState = CLK_PLL_ON;
stcPLLHInit.PLLCFGR = 0UL;
stcPLLHInit.PLLCFGR_f.PLLM = 1UL - 1UL;
stcPLLHInit.PLLCFGR_f.PLLN = 120UL - 1UL;
stcPLLHInit.PLLCFGR_f.PLLP = 4UL - 1UL;
stcPLLHInit.PLLCFGR_f.PLLQ = 4UL - 1UL;
stcPLLHInit.PLLCFGR_f.PLLR = 4UL - 1UL;
stcPLLHInit.PLLCFGR_f.PLLN = 120UL - 1UL;
#else
/* VCO = (8/1)*100 = 800MHz*/
stcPLLHInit.PLLCFGR_f.PLLN = 100UL - 1UL;
#endif
stcPLLHInit.PLLCFGR_f.PLLP = 4UL - 1UL;
stcPLLHInit.PLLCFGR_f.PLLQ = 4UL - 1UL;
stcPLLHInit.PLLCFGR_f.PLLR = 4UL - 1UL;
stcPLLHInit.PLLCFGR_f.PLLSRC = CLK_PLL_SRC_XTAL;
(void)CLK_PLLInit(&stcPLLHInit);
#ifdef BSP_USING_USB
/* Highspeed SRAM set to 0 Read/Write wait cycle */
SRAM_SetWaitCycle(SRAM_SRAMH, SRAM_WAIT_CYCLE0, SRAM_WAIT_CYCLE0);
/* SRAM1_2_3_4_backup set to 1 Read/Write wait cycle */
SRAM_SetWaitCycle((SRAM_SRAM123 | SRAM_SRAM4 | SRAM_SRAMB), SRAM_WAIT_CYCLE1, SRAM_WAIT_CYCLE1);
#else
/* Highspeed SRAM set to 1 Read/Write wait cycle */
SRAM_SetWaitCycle(SRAM_SRAMH, SRAM_WAIT_CYCLE1, SRAM_WAIT_CYCLE1);
/* SRAM1_2_3_4_backup set to 2 Read/Write wait cycle */
SRAM_SetWaitCycle((SRAM_SRAM123 | SRAM_SRAM4 | SRAM_SRAMB), SRAM_WAIT_CYCLE2, SRAM_WAIT_CYCLE2);
#endif
/* 0-wait @ 40MHz */
(void)EFM_SetWaitCycle(EFM_WAIT_CYCLE5);
EFM_SetWaitCycle(EFM_WAIT_CYCLE5);
/* 4 cycles for 200 ~ 250MHz */
GPIO_SetReadWaitCycle(GPIO_RD_WAIT4);
CLK_SetSysClockSrc(CLK_SYSCLK_SRC_PLL);
@@ -98,7 +116,7 @@ void PeripheralClockConfig(void)
CLK_SetCANClockSrc(CLK_CAN2, CLK_CANCLK_SYSCLK_DIV6);
#endif
#if defined(RT_USING_ADC)
#if defined(BSP_USING_ADC)
CLK_SetPeriClockSrc(CLK_PERIPHCLK_PCLK);
#endif
}
@@ -117,12 +135,26 @@ void SysTickConfiguration(void)
void SysTick_Handler(void)
{
x_base lock = 0;
lock = DISABLE_INTERRUPT();
TickAndTaskTimesliceUpdate();
ENABLE_INTERRUPT(lock);
}
struct InitSequenceDesc _board_init[] =
{
{ " NONE ",NONE },
{
#ifdef BSP_USING_SDIO
{ "sdio", HwSdioInit },
#endif
#ifdef BSP_USING_SPI
{ "spi", HwSpiInit },
#endif
#ifdef BSP_USING_USB
{ "usb", HwUsbHostInit },
#endif
{ " NONE ", NONE },
};
void InitBoardHardware()
+2 -2
View File
@@ -35,11 +35,11 @@ Modification:
#include <stdint.h>
extern int __bss_end;
extern int __heap_start;
extern unsigned int g_service_table_start;
extern unsigned int g_service_table_end;
#define MEMORY_START_ADDRESS (&__bss_end)
#define MEMORY_START_ADDRESS (&__heap_start)
#define HC32F4_SRAM_SIZE 512
#define MEMORY_END_ADDRESS (0x1FFE0000 + HC32F4_SRAM_SIZE * 1024)
+2 -4
View File
@@ -216,20 +216,18 @@ SECTIONS
__end__ = .;
PROVIDE(end = .);
PROVIDE(_end = .);
*(.heap*)
. = ALIGN(8);
__HeapLimit = .;
__StackLimit = .;
*(.stack*)
. = ALIGN(8);
__StackTop = .;
__heap_start = .;
} >RAM
.ARM.attributes 0 : { *(.ARM.attributes) }
PROVIDE(_stack = __StackTop);
PROVIDE(_Min_Heap_Size = __HeapLimit - __HeapBase);
PROVIDE(_Min_Stack_Size = __StackTop - __StackLimit);
__RamEnd = ORIGIN(RAM) + LENGTH(RAM);
@@ -5,3 +5,27 @@ menuconfig BSP_USING_UART
if BSP_USING_UART
source "$BSP_DIR/third_party_driver/usart/Kconfig"
endif
menuconfig BSP_USING_SPI
bool "Using SPI device"
default n
select RESOURCES_SPI
if BSP_USING_SPI
source "$BSP_DIR/third_party_driver/spi/Kconfig"
endif
menuconfig BSP_USING_SDIO
bool "Using SD CARD device"
default n
select RESOURCES_SDIO
if BSP_USING_SDIO
source "$BSP_DIR/third_party_driver/sdio/Kconfig"
endif
menuconfig BSP_USING_USB
bool "Using USB device"
default n
select RESOURCES_USB
if BSP_USING_USB
source "$BSP_DIR/third_party_driver/usb/Kconfig"
endif
@@ -4,4 +4,16 @@ ifeq ($(CONFIG_BSP_USING_UART),y)
SRC_DIR += usart
endif
ifeq ($(CONFIG_BSP_USING_SPI),y)
SRC_DIR += spi
endif
ifeq ($(CONFIG_BSP_USING_SDIO),y)
SRC_DIR += sdio
endif
ifeq ($(CONFIG_BSP_USING_USB),y)
SRC_DIR += usb
endif
include $(KERNEL_ROOT)/compiler.mk
@@ -101,7 +101,7 @@ extern "C"
#define LL_TMRA_ENABLE (DDL_ON)
#define LL_TRNG_ENABLE (DDL_ON)
#define LL_USART_ENABLE (DDL_ON)
#define LL_USB_ENABLE (DDL_OFF)
#define LL_USB_ENABLE (DDL_ON)
#define LL_VREF_ENABLE (DDL_OFF)
#define LL_WDT_ENABLE (DDL_ON)
@@ -4,4 +4,16 @@ ifeq ($(CONFIG_BSP_USING_UART),y)
SRC_FILES += hc32_ll_usart.c
endif
ifeq ($(CONFIG_BSP_USING_SDIO),y)
SRC_FILES += hc32_ll_sdioc.c
endif
ifeq ($(CONFIG_BSP_USING_SPI),y)
SRC_FILES += hc32_ll_spi.c
endif
ifeq ($(CONFIG_BSP_USING_USB),y)
SRC_FILES += hc32_ll_usb.c
endif
include $(KERNEL_ROOT)/compiler.mk
@@ -0,0 +1,42 @@
/*
* Copyright (c) 2020 AIIT XUOS Lab
* XiUOS is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
/**
* @file connect_sdio.h
* @brief define hc32f4a0-board sdio function and struct
* @version 2.0
* @author AIIT XUOS Lab
* @date 2022-03-15
*/
#ifndef CONNECT_SDIO_H
#define CONNECT_SDIO_H
#include <device.h>
#include <hc32_ll_gpio.h>
#include <hc32_ll_fcg.h>
#include <hc32_ll_sdioc.h>
#include <hardware_sdio.h>
#ifdef __cplusplus
extern "C" {
#endif
#define SD_CARD_STACK_SIZE 2048
int HwSdioInit(void);
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,39 @@
/*
* Copyright (c) 2020 AIIT XUOS Lab
* XiUOS is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
/**
* @file connect_spi.h
* @brief define hc32f4a0-board spi function and struct
* @version 2.0
* @author AIIT XUOS Lab
* @date 2022-10-17
*/
#ifndef CONNECT_SPI_H
#define CONNECT_SPI_H
#include <device.h>
#include <hardware_irq.h>
#include <hc32_ll_spi.h>
#include <hc32_ll_gpio.h>
#ifdef __cplusplus
extern "C" {
#endif
int HwSpiInit(void);
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,61 @@
/*
* Copyright (c) 2020 AIIT XUOS Lab
* XiUOS is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
/**
* @file connect_spi_lora.h
* @brief define spi lora dev function and struct using bus driver framework
* @version 2.0
* @author AIIT XUOS Lab
* @date 2022-10-31
*/
#ifndef CONNECT_SPI_LORA_H
#define CONNECT_SPI_LORA_H
#include <device.h>
#include <hc32_ll_utility.h>
#include <connect_spi.h>
#include <radio.h>
#include <spi_lora_sx12xx.h>
#include <sx1276.h>
#include <sx1276-Hal.h>
#include <sx1276-LoRa.h>
#include <sx1276-LoRaMisc.h>
#ifdef __cplusplus
extern "C" {
#endif
//#define SPI_LORA_FREQUENCY 10000000
#define SPI_LORA_BUFFER_SIZE 256
typedef struct SpiLoraDevice *SpiLoraDeviceType;
struct LoraDevDone
{
uint32 (*open) (void *dev);
uint32 (*close) (void *dev);
uint32 (*write) (void *dev, struct BusBlockWriteParam *write_param);
uint32 (*read) (void *dev, struct BusBlockReadParam *read_param);
};
struct SpiLoraDevice
{
struct SpiHardwareDevice *spi_dev;
struct SpiHardwareDevice lora_dev;
};
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,54 @@
/*
* Copyright (c) 2020 AIIT XUOS Lab
* XiUOS is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
/**
* @file connect_usb.h
* @brief define hc32f4a0-board usb function and struct
* @version 2.0
* @author AIIT XUOS Lab
* @date 2022-11-07
*/
#ifndef CONNECT_USB_H
#define CONNECT_USB_H
#include <device.h>
#include <hc32_ll_utility.h>
#include <hc32_ll_gpio.h>
#include <usb_lib.h>
#include <usb_host_user.h>
#include <usb_host_driver.h>
#include <usb_host_core.h>
#include <usb_host_msc_class.h>
#include <usb_host_msc_scsi.h>
#include <usb_host_msc_bot.h>
#include <usb_host_int.h>
#if defined(FS_VFS)
#include <iot-vfs.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
#define USB_HOST_STACK_SIZE 4096
#define USB_SINGLE_BLOCK_SIZE 512
int HwUsbHostInit(void);
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,298 @@
/**
*******************************************************************************
* @file sdioc/sdioc_sd/source/sd.h
* @brief This file contains all the functions prototypes of the Secure
* Digital(SD) driver library.
@verbatim
Change Logs:
Date Author Notes
2022-03-31 CDT First version
@endverbatim
*******************************************************************************
* Copyright (C) 2022, Xiaohua Semiconductor Co., Ltd. All rights reserved.
*
* This software component is licensed by XHSC under BSD 3-Clause license
* (the "License"); You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
*******************************************************************************
*/
/**
* @file hardware_sdio.h
* @brief define hc32f4a0-board sdio function and struct
* @version 2.0
* @author AIIT XUOS Lab
* @date 2022-10-18
*/
#ifndef __HARDWARE_SDIO_H__
#define __HARDWARE_SDIO_H__
/* C binding of definitions if building with C++ compiler */
#ifdef __cplusplus
extern "C"
{
#endif
/*******************************************************************************
* Include files
******************************************************************************/
#include "hc32_ll_sdioc.h"
#include "hc32_ll_dma.h"
#include "hc32_ll_utility.h"
/**
* @addtogroup HC32F4A0_DDL_Examples
* @{
*/
/**
* @addtogroup SDIOC_SD_Card
* @{
*/
/*******************************************************************************
* Global type definitions ('typedef')
******************************************************************************/
/**
* @defgroup SD_Global_Types SD Global Types
* @{
*/
/**
* @brief SD Card State enumeration structure definition
*/
typedef enum {
SD_CARD_STAT_IDLE = 0x00U, /*!< Card state is idle */
SD_CARD_STAT_RDY = 0x01U, /*!< Card state is ready */
SD_CARD_STAT_IDENTIFY = 0x02U, /*!< Card is in identification state */
SD_CARD_STAT_STANDBY = 0x03U, /*!< Card is in standby state */
SD_CARD_STAT_TRANS = 0x04U, /*!< Card is in transfer state */
SD_CARD_STAT_TX_DATA = 0x05U, /*!< Card is sending an operation */
SD_CARD_STAT_RX_DATA = 0x06U, /*!< Card is receiving operation information */
SD_CARD_STAT_PGM = 0x07U, /*!< Card is in programming state */
SD_CARD_STAT_DISCONNECT = 0x08U /*!< Card is disconnected */
} en_sd_card_state_t;
/**
* @brief SD Card Information Structure definition
*/
typedef struct {
uint32_t u32CardType; /*!< Specifies the card Type */
uint32_t u32CardVersion; /*!< Specifies the card version */
uint32_t u32Class; /*!< Specifies the class of the card class */
uint32_t u32RelativeCardAddr; /*!< Specifies the Relative Card Address */
uint32_t u32BlockNum; /*!< Specifies the Card Capacity in blocks */
uint32_t u32BlockSize; /*!< Specifies one block size in bytes */
uint32_t u32LogBlockNum; /*!< Specifies the Card logical Capacity in blocks */
uint32_t u32LogBlockSize; /*!< Specifies logical block size in bytes */
} stc_sd_card_info_t;
/**
* @brief SD Card Specific Data(CSD Register) Structure definition
*/
typedef struct {
uint8_t u8CSDStruct; /*!< CSD structure */
uint8_t u8Reserved1; /*!< Reserved */
uint8_t u8TAAC; /*!< Data read access time 1 */
uint8_t u8NSAC; /*!< Data read access time 2 in CLK cycles */
uint8_t u8MaxBusClkFreq; /*!< Max. bus clock frequency */
uint16_t u16CardCmdClass; /*!< Card command classes */
uint8_t u8ReadBlockLen; /*!< Max. read data block length */
uint8_t u8BlockReadPartial; /*!< Partial blocks for read allowed */
uint8_t u8WriteBlockMisalign; /*!< Write block misalignment */
uint8_t u8ReadBlockMisalign; /*!< Read block misalignment */
uint8_t u8DSRImplement; /*!< DSR implemented */
uint8_t u8Reserved2; /*!< Reserved */
uint32_t u32DeviceSize; /*!< Device Size */
uint8_t u8MaxReadCurrVDDMin; /*!< Max. read current @ VDD min */
uint8_t u8MaxReadCurrVDDMax; /*!< Max. read current @ VDD max */
uint8_t u8MaxWriteCurrVDDMin; /*!< Max. write current @ VDD min */
uint8_t u8MaxWriteCurrVDDMax; /*!< Max. write current @ VDD max */
uint8_t u8DeviceSizeMul; /*!< Device size multiplier */
uint8_t u8EraseSingleBlockEn; /*!< Erase single block enable */
uint8_t u8EraseSectorSize; /*!< Erase sector size */
uint8_t u8WriteProtectGroupSize; /*!< Write protect group size */
uint8_t u8WriteProtectGroupEn; /*!< Write protect group enable */
uint8_t u8Reserved3; /*!< Reserved */
uint8_t u8WriteSpeedFactor; /*!< Write speed factor */
uint8_t u8MaxWriteBlockLen; /*!< Max. write data block length */
uint8_t u8WriteBlockPartial; /*!< Partial blocks for write allowed */
uint8_t u8Reserved4; /*!< Reserved */
uint8_t u8FileFormatGroup; /*!< File format group */
uint8_t u8CopyFlag; /*!< Copy flag (OTP) */
uint8_t u8PermWriteProtect; /*!< Permanent write protection */
uint8_t u8TempWriteProtect; /*!< Temporary write protection */
uint8_t u8FileFormat; /*!< File format */
uint8_t u8Reserved5; /*!< Reserved */
uint8_t u8CRCChecksum; /*!< CSD CRC7 checksum */
uint8_t u8Reserved6; /*!< Always 1 */
} stc_sd_card_csd_t;
/**
* @brief SD Card Identification Data(CID Register) Structure definition
*/
typedef struct {
uint8_t u8ManufacturerID; /*!< Manufacturer ID */
uint16_t u16OemAppID; /*!< OEM/Application ID */
uint32_t u32ProductName1; /*!< Product Name part1 */
uint8_t u8ProductName2; /*!< Product Name part2 */
uint8_t u8ProductRevision; /*!< Product Revision */
uint32_t u32ProductSN; /*!< Product Serial Number */
uint8_t u8Reserved1; /*!< Reserved1 */
uint16_t u16ManufactDate; /*!< Manufacturing Date */
uint8_t u8CRCChecksum; /*!< CRC7 checksum */
uint8_t u8Reserved2; /*!< Always 1 */
} stc_sd_card_cid_t;
/**
* @brief SD Card Status Structure definition (returned by ACMD13)
*/
typedef struct {
uint8_t u8DataBusWidth; /*!< Shows the currently defined data bus width */
uint8_t u8SecuredMode; /*!< Card is in secured mode of operation */
uint16_t u16CardType; /*!< Carries information about card type */
uint32_t u32ProtectedAreaSize; /*!< Carries information about the capacity of protected area */
uint8_t u8SpeedClass; /*!< Carries information about the speed class of the card */
uint8_t u8PerformanceMove; /*!< Carries information about the card's performance move */
uint8_t u8AllocUnitSize; /*!< Carries information about the card's allocation unit size */
uint16_t u16EraseSize; /*!< Determines the number of AUs to be erased in one operation */
uint8_t u8EraseTimeout; /*!< Determines the timeout for any number of AU erase */
uint8_t u8EraseOffset; /*!< Carries information about the erase offset */
} stc_sd_card_status_t;
/**
* @brief SD handle Structure definition
*/
typedef struct {
CM_SDIOC_TypeDef *SDIOCx; /*!< Pointer to SDIOC registers base address */
stc_sdioc_init_t stcSdiocInit; /*!< SDIOC Initialize structure @ref stc_sdioc_init_t */
CM_DMA_TypeDef *DMAx; /*!< Pointer to DMA registers base address */
uint8_t u8DmaTxCh; /*!< Specifies the DMA channel used to send */
uint8_t u8DmaRxCh; /*!< Specifies the DMA channel used to receive */
uint8_t *pu8Buffer; /*!< Pointer to SD Tx/Rx transfer Buffer */
uint32_t u32Len; /*!< SD Tx/Rx Transfer length */
uint32_t u32Context; /*!< SD transfer context */
uint32_t u32ErrorCode; /*!< SD Card Error codes */
stc_sd_card_info_t stcSdCardInfo; /*!< SD Card information */
uint32_t u32CSD[4]; /*!< SD card specific data table */
uint32_t u32CID[4]; /*!< SD card identification number table */
uint32_t u32SCR[2]; /*!< SD Configuration Register table */
} stc_sd_handle_t;
/**
* @}
*/
/*******************************************************************************
* Global pre-processor symbols/macros ('#define')
******************************************************************************/
/**
* @defgroup SD_Global_Macros SD Global Macros
* @{
*/
/**
* @defgroup SD_Transfer_Context SD Transfer Context
* @{
*/
#define SD_CONTEXT_NONE (0x00UL) /*!< None */
#define SD_CONTEXT_RD_SINGLE_BLOCK (0x01UL) /*!< Read single block operation */
#define SD_CONTEXT_RD_MULTI_BLOCK (0x02UL) /*!< Read multiple blocks operation */
#define SD_CONTEXT_WR_SINGLE_BLOCK (0x10UL) /*!< Write single block operation */
#define SD_CONTEXT_WR_MULTI_BLOCK (0x20UL) /*!< Write multiple blocks operation */
#define SD_CONTEXT_INT (0x40UL) /*!< Process in Interrupt mode */
#define SD_CONTEXT_DMA (0x80UL) /*!< Process in DMA mode */
/**
* @}
*/
/**
* @defgroup SD_Support_Memory_Card SD Support Memory Card
* @{
*/
#define SD_CARD_SDSC (0x00UL)
#define SD_CARD_SDHC_SDXC (0x01UL)
#define SD_CARD_SECURED (0x03UL)
/**
* @}
*/
/**
* @defgroup SD_Support_Version SD Support Version
* @{
*/
#define SD_CARD_V1_X (0x00UL) /*!< SD Card version: 1.x */
#define SD_CARD_V2_X (0x01UL) /*!< SD Card version: 2.x */
/**
* @}
*/
/**
* @}
*/
/*******************************************************************************
* Global variable definitions ('extern')
******************************************************************************/
/*******************************************************************************
Global function prototypes (definition in C source)
******************************************************************************/
/**
* @addtogroup SD_Global_Functions
* @{
*/
int32_t SD_DeInit(stc_sd_handle_t *handle);
int32_t SD_Init(stc_sd_handle_t *handle);
int32_t SD_GetCardState(stc_sd_handle_t *handle, en_sd_card_state_t *peCardState);
int32_t SD_GetCardCID(const stc_sd_handle_t *handle, stc_sd_card_cid_t *pstcCardCID);
int32_t SD_GetCardCSD(stc_sd_handle_t *handle, stc_sd_card_csd_t *pstcCardCSD);
int32_t SD_GetCardStatus(stc_sd_handle_t *handle, stc_sd_card_status_t *pstcCardStatus);
int32_t SD_GetCardInfo(stc_sd_handle_t *handle, stc_sd_card_info_t *pstcCardInfo);
int32_t SD_GetErrorCode(const stc_sd_handle_t *handle, uint32_t *pu32ErrorCode);
/* Callback in non blocking modes */
void SD_IRQHandler(stc_sd_handle_t *handle);
void SD_TxCompleteCallback(stc_sd_handle_t *handle);
void SD_RxCompleteCallback(stc_sd_handle_t *handle);
void SD_ErrorCallback(stc_sd_handle_t *handle);
/* Polling Mode */
int32_t SD_Erase(stc_sd_handle_t *handle, uint32_t u32BlockStartAddr, uint32_t u32BlockEndAddr);
int32_t SD_ReadBlocks(stc_sd_handle_t *handle, uint32_t u32BlockAddr, uint16_t u16BlockCount,
uint8_t *pu8Data, uint32_t u32Timeout);
int32_t SD_WriteBlocks(stc_sd_handle_t *handle, uint32_t u32BlockAddr, uint16_t u16BlockCount,
uint8_t *pu8Data, uint32_t u32Timeout);
/* Interrupt Mode */
int32_t SD_ReadBlocks_INT(stc_sd_handle_t *handle, uint32_t u32BlockAddr, uint16_t u16BlockCount, uint8_t *pu8Data);
int32_t SD_WriteBlocks_INT(stc_sd_handle_t *handle, uint32_t u32BlockAddr, uint16_t u16BlockCount, uint8_t *pu8Data);
/* DMA Mode */
int32_t SD_ReadBlocks_DMA(stc_sd_handle_t *handle, uint32_t u32BlockAddr, uint16_t u16BlockCount, uint8_t *pu8Data);
int32_t SD_WriteBlocks_DMA(stc_sd_handle_t *handle, uint32_t u32BlockAddr, uint16_t u16BlockCount, uint8_t *pu8Data);
/* Abort */
int32_t SD_Abort(stc_sd_handle_t *handle);
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* __SD_H__ */
/*******************************************************************************
* EOF (not truncated)
******************************************************************************/
@@ -0,0 +1,24 @@
if BSP_USING_SDIO
config SDIO_BUS_NAME
string "sdio bus name"
default "sdio"
config SDIO_DRIVER_NAME
string "sdio driver name"
default "sdio_drv"
config SDIO_DEVICE_NAME
string "sdio device name"
default "sdio_dev"
config MOUNT_SDCARD_FS
bool "mount sd card file system : if y then not support usb-mount-fs"
default y
select MOUNT_SDCARD
if MOUNT_SDCARD_FS
config MOUNT_SDCARD_FS_TYPE
int "choose file system type : FATFS(0)"
default 0
endif
endif
@@ -0,0 +1,3 @@
SRC_FILES := connect_sdio.c hardware_sdio.c
include $(KERNEL_ROOT)/compiler.mk
@@ -0,0 +1,349 @@
/**
*******************************************************************************
* @file sdioc/sdioc_sd/source/main.c
* @brief Main program of SDIOC SD card for the Device Driver Library.
@verbatim
Change Logs:
Date Author Notes
2022-03-31 CDT First version
@endverbatim
*******************************************************************************
* Copyright (C) 2022, Xiaohua Semiconductor Co., Ltd. All rights reserved.
*
* This software component is licensed by XHSC under BSD 3-Clause license
* (the "License"); You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
*******************************************************************************
*/
/**
* @file connect_sdio.c
* @brief support sdio function using bus driver framework on hc32f4a0 board
* @version 2.0
* @author AIIT XUOS Lab
* @date 2022-10-18
*/
/*************************************************
File name: connect_sdio.c
Description: support hc32f4a0-board sd card configure and sdio bus register function
Others:
History:
1. Date: 2022-01-24
Author: AIIT XUOS Lab
Modification:
1. support hc32f4a0-board sdio configure, write and read
2. support hc32f4a0-board sdio bus device and driver register
*************************************************/
#include <connect_sdio.h>
/* SD transfer mode */
#define SD_TRANS_MD_POLLING (0U)
#define SD_TRANS_MD_INT (1U)
#define SD_TRANS_MD_DMA (2U)
/* Populate the following macro with an value, reference "SD transfer mode" */
#define SD_TRANS_MD (SD_TRANS_MD_POLLING)
/* SDIOC configuration define */
#define SDIOC_SD_UINT (CM_SDIOC1)
#define SDIOC_SD_CLK (FCG1_PERIPH_SDIOC1)
/* CD = PB13 */
#define SDIOC_CD_PORT (GPIO_PORT_B)
#define SDIOC_CD_PIN (GPIO_PIN_13)
/* CK = PC12 */
#define SDIOC_CK_PORT (GPIO_PORT_C)
#define SDIOC_CK_PIN (GPIO_PIN_12)
/* CMD = PD02 */
#define SDIOC_CMD_PORT (GPIO_PORT_D)
#define SDIOC_CMD_PIN (GPIO_PIN_02)
/* D0 = PB07 */
#define SDIOC_D0_PORT (GPIO_PORT_B)
#define SDIOC_D0_PIN (GPIO_PIN_07)
/* D1 = PA08 */
#define SDIOC_D1_PORT (GPIO_PORT_A)
#define SDIOC_D1_PIN (GPIO_PIN_08)
/* D2 = PC10 */
#define SDIOC_D2_PORT (GPIO_PORT_C)
#define SDIOC_D2_PIN (GPIO_PIN_10)
/* D3 = PB05 */
#define SDIOC_D3_PORT (GPIO_PORT_B)
#define SDIOC_D3_PIN (GPIO_PIN_05)
static stc_sd_handle_t gSdHandle;
static int sd_lock = -1;
static void SdCardConfig(void)
{
/* Enable SDIOC clock */
FCG_Fcg1PeriphClockCmd(SDIOC_SD_CLK, ENABLE);
/* SDIOC pins configuration */
stc_gpio_init_t stcGpioInit;
(void)GPIO_StructInit(&stcGpioInit);
stcGpioInit.u16PinState = PIN_STAT_RST;
stcGpioInit.u16PinDir = PIN_DIR_IN;
(void)GPIO_Init(SDIOC_CD_PORT, SDIOC_CD_PIN, &stcGpioInit);
GPIO_SetFunc(SDIOC_CK_PORT, SDIOC_CK_PIN, GPIO_FUNC_9);
GPIO_SetFunc(SDIOC_CMD_PORT, SDIOC_CMD_PIN, GPIO_FUNC_9);
GPIO_SetFunc(SDIOC_D0_PORT, SDIOC_D0_PIN, GPIO_FUNC_9);
GPIO_SetFunc(SDIOC_D1_PORT, SDIOC_D1_PIN, GPIO_FUNC_9);
GPIO_SetFunc(SDIOC_D2_PORT, SDIOC_D2_PIN, GPIO_FUNC_9);
GPIO_SetFunc(SDIOC_D3_PORT, SDIOC_D3_PIN, GPIO_FUNC_9);
/* Configure structure initialization */
gSdHandle.SDIOCx = SDIOC_SD_UINT;
gSdHandle.stcSdiocInit.u32Mode = SDIOC_MD_SD;
gSdHandle.stcSdiocInit.u8CardDetect = SDIOC_CARD_DETECT_CD_PIN_LVL;
gSdHandle.stcSdiocInit.u8SpeedMode = SDIOC_SPEED_MD_HIGH;
gSdHandle.stcSdiocInit.u8BusWidth = SDIOC_BUS_WIDTH_4BIT;
gSdHandle.stcSdiocInit.u16ClockDiv = SDIOC_CLK_DIV2;
gSdHandle.DMAx = NULL;
}
static uint32 SdioConfigure(void *drv, struct BusConfigureInfo *configure_info)
{
NULL_PARAM_CHECK(drv);
NULL_PARAM_CHECK(configure_info);
if (configure_info->configure_cmd == OPER_BLK_GETGEOME) {
NULL_PARAM_CHECK(configure_info->private_data);
struct DeviceBlockArrange *args = (struct DeviceBlockArrange *)configure_info->private_data;
args->size_perbank = gSdHandle.stcSdCardInfo.u32BlockSize;
args->block_size = gSdHandle.stcSdCardInfo.u32BlockSize;
args->bank_num = gSdHandle.stcSdCardInfo.u32BlockNum;
}
return EOK;
}
static uint32 SdioOpen(void *dev)
{
NULL_PARAM_CHECK(dev);
if(sd_lock >= 0) {
KSemaphoreDelete(sd_lock);
}
sd_lock = KSemaphoreCreate(1);
if (sd_lock < 0){
return ERROR;
}
return EOK;
}
static uint32 SdioClose(void *dev)
{
NULL_PARAM_CHECK(dev);
KSemaphoreDelete(sd_lock);
return EOK;
}
static uint32 SdioRead(void *dev, struct BusBlockReadParam *read_param)
{
uint8 ret = EOK;
uint32 sector = read_param->pos;
uint32 block_num = read_param->size;
uint8 *read_buffer = (uint8 *)read_param->buffer;
KSemaphoreObtain(sd_lock, WAITING_FOREVER);
if (LL_OK != SD_ReadBlocks(&gSdHandle, sector, block_num, read_buffer, 2000UL)) {
KPrintf("Read data blocks failed.\r\n");
return 0;
}
KSemaphoreAbandon(sd_lock);
return read_param->size;
}
static uint32 SdioWrite(void *dev, struct BusBlockWriteParam *write_param)
{
uint8 ret = EOK;
uint32 sector = write_param->pos;
uint32 block_num = write_param->size;
uint8 *write_buffer = (uint8 *)write_param->buffer;
KSemaphoreObtain(sd_lock, WAITING_FOREVER);
if (LL_OK != SD_WriteBlocks(&gSdHandle, sector, block_num, write_buffer, 2000U)) {
KPrintf("Write data blocks failed.\r\n");
return 0;
}
KSemaphoreAbandon(sd_lock);
return write_param->size;
}
static int SdioControl(struct HardwareDev *dev, struct HalDevBlockParam *block_param)
{
NULL_PARAM_CHECK(dev);
if (OPER_BLK_GETGEOME == block_param->cmd) {
block_param->dev_block.size_perbank = gSdHandle.stcSdCardInfo.u32BlockSize;
block_param->dev_block.block_size = gSdHandle.stcSdCardInfo.u32BlockSize;
block_param->dev_block.bank_num = gSdHandle.stcSdCardInfo.u32BlockNum;
}
return EOK;
}
static struct SdioDevDone dev_done =
{
SdioOpen,
SdioClose,
SdioWrite,
SdioRead,
};
#if defined(FS_VFS) && defined(MOUNT_SDCARD_FS)
#include <iot-vfs.h>
/**
* @description: Mount SD card
* @return 0
*/
static int MountSDCardFs(enum FilesystemType fs_type)
{
if (MountFilesystem(SDIO_BUS_NAME, SDIO_DEVICE_NAME, SDIO_DRIVER_NAME, fs_type, "/") == 0)
KPrintf("Sd card mount to '/'");
else
KPrintf("Sd card mount to '/' failed!");
return 0;
}
#endif
static void SdCardAttach(void)
{
static stc_sd_handle_t *sd_handle = &gSdHandle;
KPrintf("\r\nCard inserted.\r\n");
/* Reset and init SDIOC */
if (LL_OK != SDIOC_SWReset(sd_handle->SDIOCx, SDIOC_SW_RST_ALL)) {
KPrintf("Reset SDIOC failed!\r\n");
} else if (LL_OK != SD_Init(sd_handle)) {
KPrintf("SD card initialize failed!\r\n");
} else {
KPrintf("SD card init done!\r\n");
}
#ifdef MOUNT_SDCARD_FS
/*mount file system*/
MountSDCardFs(MOUNT_SDCARD_FS_TYPE);
#endif
}
static void SdCardDetach(void)
{
/*unmount file system*/
KPrintf("\r\nCard detect extracted.\r\n");
#ifdef MOUNT_SDCARD_FS
UnmountFileSystem("/");
#endif
}
static uint8 SdCardReadCd(void)
{
en_pin_state_t sd_cd_state = GPIO_ReadInputPins(SDIOC_CD_PORT, SDIOC_CD_PIN);
if (PIN_RESET == sd_cd_state) {
return 0;
} else {
return 1;
}
}
static void SdCardTask(void* parameter)
{
static int sd_card_status = 0;
while (1) {
if (!SdCardReadCd()) {
if (!sd_card_status) {
SdCardAttach();
sd_card_status = 1;
}
} else {
if (sd_card_status) {
SdCardDetach();
sd_card_status = 0;
}
}
}
}
#ifdef MOUNT_SDCARD
int MountSDCard()
{
int sd_card_task = 0;
sd_card_task = KTaskCreate("sd_card", SdCardTask, NONE,
SD_CARD_STACK_SIZE, 8);
if(sd_card_task < 0) {
KPrintf("sd_card_task create failed ...%s %d.\n", __FUNCTION__,__LINE__);
return ERROR;
}
StartupKTask(sd_card_task);
return EOK;
}
#endif
int HwSdioInit(void)
{
x_err_t ret = EOK;
static struct SdioBus sdio_bus;
static struct SdioDriver sdio_drv;
static struct SdioHardwareDevice sdio_dev;
memset(&sdio_bus, 0, sizeof(struct SdioBus));
memset(&sdio_drv, 0, sizeof(struct SdioDriver));
memset(&sdio_dev, 0, sizeof(struct SdioHardwareDevice));
SdCardConfig();
ret = SdioBusInit(&sdio_bus, SDIO_BUS_NAME);
if (ret != EOK) {
KPrintf("Sdio bus init error %d\n", ret);
return ERROR;
}
ret = SdioDriverInit(&sdio_drv, SDIO_DRIVER_NAME);
if (ret != EOK) {
KPrintf("Sdio driver init error %d\n", ret);
return ERROR;
}
ret = SdioDriverAttachToBus(SDIO_DRIVER_NAME, SDIO_BUS_NAME);
if (ret != EOK) {
KPrintf("Sdio driver attach error %d\n", ret);
return ERROR;
}
sdio_dev.dev_done = &dev_done;
sdio_dev.haldev.dev_block_control = SdioControl;
ret = SdioDeviceRegister(&sdio_dev, SDIO_DEVICE_NAME);
if (ret != EOK) {
KPrintf("Sdio device register error %d\n", ret);
return ERROR;
}
ret = SdioDeviceAttachToBus(SDIO_DEVICE_NAME, SDIO_BUS_NAME);
if (ret != EOK) {
KPrintf("Sdio device register error %d\n", ret);
return ERROR;
}
return ret;
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,42 @@
if BSP_USING_SPI
config BSP_USING_SPI1
bool "Using spi1"
default y
if BSP_USING_SPI1
config SPI_BUS_NAME_1
string "spi bus 1 name"
default "spi1"
config SPI_1_DEVICE_NAME_0
string "spi bus 1 device 0 name"
default "spi1_dev0"
config SPI_1_DRV_NAME
string "spi bus 1 driver name"
default "spi1_drv"
menuconfig RESOURCES_SPI_LORA
bool "Using spi lora function"
default n
if RESOURCES_SPI_LORA
config SX12XX_DEVICE_NAME
string "SX12XX(SX1278 SX1276) lora device name"
default "spi1_lora"
endif
endif
config BSP_USING_SPI6
bool "Using spi6"
default n
if BSP_USING_SPI6
config SPI_BUS_NAME_6
string "spi bus 6 name"
default "spi6"
config SPI_6_DEVICE_NAME_0
string "spi bus 6 device 0 name"
default "spi6_dev0"
config SPI_6_DRV_NAME
string "spi bus 6 driver name"
default "spi6_drv"
endif
endif
@@ -0,0 +1,8 @@
SRC_FILES := connect_spi.c
ifeq ($(CONFIG_RESOURCES_SPI_LORA),y)
SRC_DIR := third_party_spi_lora
SRC_FILES += connect_lora_spi.c
endif
include $(KERNEL_ROOT)/compiler.mk
@@ -0,0 +1,469 @@
/*
* Copyright (c) 2020 AIIT XUOS Lab
* XiUOS is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
/**
* @file connect_lora_spi.c
* @brief support to register spi lora pointer and function
* @version 2.0
* @author AIIT XUOS Lab
* @date 2022-10-31
*/
#include <connect_spi_lora.h>
/* RST = PI02 */
#define LORA_RST_PORT (GPIO_PORT_I)
#define LORA_RST_PIN (GPIO_PIN_02)
static struct HardwareDev *g_spi_lora_dev;
tRadioDriver *Radio = NONE;
void SX1276InitIo(void)
{
stc_gpio_init_t stcGpioInit;
(void)GPIO_StructInit(&stcGpioInit);
stcGpioInit.u16PinState = PIN_STAT_RST;
stcGpioInit.u16PinDir = PIN_DIR_OUT;
(void)GPIO_Init(LORA_RST_PORT, LORA_RST_PIN, &stcGpioInit);
}
inline void SX1276WriteRxTx(uint8_t txEnable)
{
if (txEnable != 0) {
/*to do*/
} else {
/*to do*/
}
}
void SX1276SetReset(uint8_t state)
{
if (state == RADIO_RESET_ON) {
GPIO_ResetPins(LORA_RST_PORT, LORA_RST_PIN);
} else {
stc_gpio_init_t stcGpioInit;
(void)GPIO_StructInit(&stcGpioInit);
stcGpioInit.u16PinDir = PIN_DIR_IN;
(void)GPIO_Init(LORA_RST_PORT, LORA_RST_PIN, &stcGpioInit);
}
}
//Not-necessary Function
uint8_t SX1276ReadDio0(void)
{
return 1;
}
uint8_t SX1276ReadDio1(void)
{
return 1;
}
uint8_t SX1276ReadDio2(void)
{
return 1;
}
uint8_t SX1276ReadDio3(void)
{
return 1;
}
uint8_t SX1276ReadDio4(void)
{
return 1;
}
uint8_t SX1276ReadDio5(void)
{
return 1;
}
void SX1276WriteBuffer(uint8_t addr, uint8_t *buffer, uint8_t size)
{
struct BusBlockWriteParam write_param;
uint8 write_addr = addr | 0x80;
BusDevOpen(g_spi_lora_dev);
write_param.buffer = (void *)&write_addr;
write_param.size = 1;
BusDevWriteData(g_spi_lora_dev, &write_param);
write_param.buffer = (void *)buffer;
write_param.size = size;
BusDevWriteData(g_spi_lora_dev, &write_param);
BusDevClose(g_spi_lora_dev);
}
void SX1276ReadBuffer(uint8_t addr, uint8_t *buffer, uint8_t size)
{
struct BusBlockWriteParam write_param;
struct BusBlockReadParam read_param;
uint8 write_addr = addr & 0x7F;
BusDevOpen(g_spi_lora_dev);
write_param.buffer = (void *)&write_addr;
write_param.size = 1;
BusDevWriteData(g_spi_lora_dev, &write_param);
read_param.buffer = (void *)buffer;
read_param.size = size;
BusDevReadData(g_spi_lora_dev, &read_param);
BusDevClose(g_spi_lora_dev);
}
void SX1276WriteFifo(uint8_t *buffer, uint8_t size)
{
SX1276WriteBuffer(0, buffer, size);
}
void SX1276ReadFifo(uint8_t *buffer, uint8_t size)
{
SX1276ReadBuffer(0, buffer, size);
}
void SX1276Write(uint8_t addr, uint8_t data)
{
SX1276WriteBuffer(addr, &data, 1);
}
void SX1276Read(uint8_t addr, uint8_t *data)
{
SX1276ReadBuffer(addr, data, 1);
}
uint8_t Sx1276SpiCheck(void)
{
uint8_t test = 0;
tLoRaSettings settings;
SX1276Read(REG_LR_VERSION, &test);
KPrintf("version code of the chip is 0x%x\n", test);
settings.RFFrequency = SX1276LoRaGetRFFrequency();
KPrintf("SX1278 Lora parameters are :\nRFFrequency is %d\n", settings.RFFrequency);
settings.Power = SX1276LoRaGetRFPower();
KPrintf("RFPower is %d\n",settings.Power);
settings.SignalBw = SX1276LoRaGetSignalBandwidth();
KPrintf("SignalBw is %d\n",settings.SignalBw);
settings.SpreadingFactor = SX1276LoRaGetSpreadingFactor();
KPrintf("SpreadingFactor is %d\n",settings.SpreadingFactor);
/*SPI confirm*/
SX1276Write(REG_LR_HOPPERIOD, 0x91);
SX1276Read(REG_LR_HOPPERIOD, &test);
if (test != 0x91) {
return 0;
}
return test;
}
/**
* This function supports to write data to the lora.
*
* @param dev lora dev descriptor
* @param write_param lora dev write datacfg param
*/
static uint32 SpiLoraWrite(void *dev, struct BusBlockWriteParam *write_param)
{
NULL_PARAM_CHECK(dev);
NULL_PARAM_CHECK(write_param);
if (write_param->size > 256) {
KPrintf("SpiLoraWrite ERROR:The message is too long!\n");
return ERROR;
} else {
SX1276SetTxPacket(write_param->buffer, write_param->size);
while(SX1276Process() != RF_TX_DONE);
KPrintf("SpiLoraWrite success!\n");
}
return EOK;
}
/**
* This function supports to read data from the lora.
*
* @param dev lora dev descriptor
* @param read_param lora dev read datacfg param
*/
static uint32 SpiLoraRead(void *dev, struct BusBlockReadParam *read_param)
{
NULL_PARAM_CHECK(dev);
NULL_PARAM_CHECK(read_param);
int read_times = 100;
SX1276StartRx();
KPrintf("SpiLoraRead Ready!\n");
while (read_times) {
if (SX1276Process() != RF_RX_DONE) {
read_times --;
MdelayKTask(500);
} else {
break;
}
}
if (read_times > 0) {
SX1276GetRxPacket(read_param->buffer, (uint16 *)&read_param->read_length);
} else {
read_param->read_length = 0;
}
return read_param->read_length;
}
static uint32 SpiLoraOpen(void *dev)
{
NULL_PARAM_CHECK(dev);
KPrintf("SpiLoraOpen start\n");
x_err_t ret = EOK;
static x_bool lora_init_status = RET_FALSE;
if (RET_TRUE == lora_init_status) {
return EOK;
}
struct HardwareDev *haldev = (struct HardwareDev *)dev;
struct SpiHardwareDevice *lora_dev = CONTAINER_OF(haldev, struct SpiHardwareDevice, haldev);
NULL_PARAM_CHECK(lora_dev);
SpiLoraDeviceType spi_lora_dev = CONTAINER_OF(lora_dev, struct SpiLoraDevice, lora_dev);
NULL_PARAM_CHECK(spi_lora_dev);
struct Driver *spi_drv = spi_lora_dev->spi_dev->haldev.owner_bus->owner_driver;
struct BusConfigureInfo configure_info;
struct SpiMasterParam spi_master_param;
spi_master_param.spi_data_bit_width = 8;
spi_master_param.spi_work_mode = SPI_MODE_0 | SPI_MSB;
configure_info.configure_cmd = OPE_CFG;
configure_info.private_data = (void *)&spi_master_param;
ret = BusDrvConfigure(spi_drv, &configure_info);
if (ret) {
KPrintf("spi drv OPE_CFG error drv %8p cfg %8p\n", spi_drv, &spi_master_param);
return ERROR;
}
configure_info.configure_cmd = OPE_INT;
ret = BusDrvConfigure(spi_drv, &configure_info);
if (ret) {
KPrintf("spi drv OPE_INT error drv %8p\n", spi_drv);
return ERROR;
}
SX1276Init();
if (0x91 != Sx1276SpiCheck()) {
KPrintf("LoRa check failed!\n!");
} else {
Radio = RadioDriverInit();
KPrintf("LoRa check ok!\nNote: The length of the message that can be sent in a single time is 256 characters\n");
}
lora_init_status = RET_TRUE;
return ret;
}
static uint32 SpiLoraClose(void *dev)
{
NULL_PARAM_CHECK(dev);
return EOK;
}
static const struct LoraDevDone lora_done =
{
.open = SpiLoraOpen,
.close = SpiLoraClose,
.write = SpiLoraWrite,
.read = SpiLoraRead,
};
/**
* This function supports to init spi_lora_dev
*
* @param bus_name spi bus name
* @param dev_name spi dev name
* @param drv_name spi drv name
* @param lora_name lora dev name
*/
SpiLoraDeviceType SpiLoraInit(char *bus_name, char *dev_name, char *drv_name, char *lora_name)
{
NULL_PARAM_CHECK(dev_name);
NULL_PARAM_CHECK(drv_name);
NULL_PARAM_CHECK(lora_name);
NULL_PARAM_CHECK(bus_name);
x_err_t ret;
static HardwareDevType haldev;
haldev = SpiDeviceFind(dev_name, TYPE_SPI_DEV);
if (NONE == haldev) {
KPrintf("SpiLoraInit find spi haldev %s error! \n", dev_name);
return NONE;
}
SpiLoraDeviceType spi_lora_dev = (SpiLoraDeviceType)malloc(sizeof(struct SpiLoraDevice));
if (NONE == spi_lora_dev) {
KPrintf("SpiLoraInit malloc spi_lora_dev failed\n");
free(spi_lora_dev);
return NONE;
}
memset(spi_lora_dev, 0, sizeof(struct SpiLoraDevice));
spi_lora_dev->spi_dev = CONTAINER_OF(haldev, struct SpiHardwareDevice, haldev);
spi_lora_dev->lora_dev.spi_dev_flag = RET_TRUE;
spi_lora_dev->lora_dev.haldev.dev_done = (struct HalDevDone *)&lora_done;
struct Driver *spi_driver = SpiDriverFind(drv_name, TYPE_SPI_DRV);
if (NONE == spi_driver) {
KPrintf("SpiLoraInit find spi driver %s error! \n", drv_name);
free(spi_lora_dev);
return NONE;
}
//spi drv get spi dev param (SpiDeviceParam)
spi_driver->private_data = spi_lora_dev->spi_dev->haldev.private_data;
spi_lora_dev->spi_dev->haldev.owner_bus->owner_driver = spi_driver;
ret = SpiDeviceRegister(&spi_lora_dev->lora_dev, spi_lora_dev->spi_dev->haldev.private_data, lora_name);
if (EOK != ret) {
KPrintf("SpiLoraInit SpiDeviceRegister device %s error %d\n", lora_name, ret);
free(spi_lora_dev);
return NONE;
}
ret = SpiDeviceAttachToBus(lora_name, bus_name);
if (EOK != ret) {
KPrintf("SpiLoraInit SpiDeviceAttachToBus device %s error %d\n", lora_name, ret);
free(spi_lora_dev);
return NONE;
}
g_spi_lora_dev = &spi_lora_dev->spi_dev->haldev;
return spi_lora_dev;
}
/**
* This function supports to release spi_lora_dev
*
* @param spi_lora_dev spi lora descriptor
*/
uint32 SpiLoraRelease(SpiLoraDeviceType spi_lora_dev)
{
NULL_PARAM_CHECK(spi_lora_dev);
x_err_t ret;
DeviceDeleteFromBus(spi_lora_dev->lora_dev.haldev.owner_bus, &spi_lora_dev->lora_dev.haldev);
free(spi_lora_dev);
return EOK;
}
int LoraSx12xxSpiDeviceInit(void)
{
#ifdef BSP_USING_SPI1
if (NONE == SpiLoraInit(SPI_BUS_NAME_1, SPI_1_DEVICE_NAME_0, SPI_1_DRV_NAME, SX12XX_DEVICE_NAME)) {
return ERROR;
}
#endif
return EOK;
}
#define LORA_TEST
#ifdef LORA_TEST
/*Just for lora test*/
static struct Bus *bus;
static struct HardwareDev *dev;
void LoraOpen(void)
{
x_err_t ret = EOK;
bus = BusFind(SPI_BUS_NAME_1);
dev = BusFindDevice(bus, SX12XX_DEVICE_NAME);
ret = SpiLoraOpen(dev);
if (EOK != ret) {
KPrintf("LoRa init failed\n");
return;
}
KPrintf("LoRa init succeed\n");
return;
}
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN),
LoraOpen, LoraOpen, open lora device and read parameters );
static void LoraReceive(void)
{
uint32 read_length = 0;
struct BusBlockReadParam read_param;
memset(&read_param, 0, sizeof(struct BusBlockReadParam));
read_param.buffer = malloc(SPI_LORA_BUFFER_SIZE);
read_length = SpiLoraRead(dev, &read_param);
KPrintf("LoraReceive length %d\n", read_length);
for (int i = 0; i < read_length; i ++) {
KPrintf("i %d data 0x%x\n", i, ((uint8 *)read_param.buffer)[i]);
}
free(read_param.buffer);
}
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC)|SHELL_CMD_PARAM_NUM(0),
LoraReceive, LoraReceive, lora wait message );
static void LoraSend(int argc, char *argv[])
{
char Msg[SPI_LORA_BUFFER_SIZE] = {0};
struct BusBlockWriteParam write_param;
memset(&write_param, 0, sizeof(struct BusBlockWriteParam));
if (argc == 2) {
strncpy(Msg, argv[1], SPI_LORA_BUFFER_SIZE);
write_param.buffer = Msg;
write_param.size = strlen(Msg);
KPrintf("LoraSend data %s length %d\n", Msg, strlen(Msg));
SpiLoraWrite(dev, &write_param);
}
}
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN),
LoraSend, LoraSend, lora send message );
#endif
@@ -0,0 +1,585 @@
/*
* Copyright (c) 2020 AIIT XUOS Lab
* XiUOS is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
/**
* @file connect_spi.c
* @brief support hc32f4a0-board spi function and register to bus framework
* @version 2.0
* @author AIIT XUOS Lab
* @date 2022-10-17
*/
/*************************************************
File name: connect_spi.c
Description: support hc32f4a0-board spi function and register to bus framework
Others:
History:
1. Date: 2022-10-17
Author: AIIT XUOS Lab
Modification:
1. support hc32f4a0-board spi configure, write and read
2. support hc32f4a0-board spi bus device and driver register
3. SPI1 for LoRa, SPI6 using J12-pin-header to connect
*************************************************/
#include <connect_spi.h>
#define SPI1_MASTER_SLAVE_MODE (SPI_MASTER)
/* SPI1 definition */
#define SPI1_UNIT (CM_SPI1)
#define SPI1_CLK (FCG1_PERIPH_SPI1)
/* SS = PI01 */
#define SPI1_SS_PORT (GPIO_PORT_I)
#define SPI1_SS_PIN (GPIO_PIN_01)
/* SCK = PH14 */
#define SPI1_SCK_PORT (GPIO_PORT_H)
#define SPI1_SCK_PIN (GPIO_PIN_14)
#define SPI1_SCK_FUNC (GPIO_FUNC_40)
/* MOSI = PI00 */
#define SPI1_MOSI_PORT (GPIO_PORT_I)
#define SPI1_MOSI_PIN (GPIO_PIN_00)
#define SPI1_MOSI_FUNC (GPIO_FUNC_41)
/* MISO = PH15 */
#define SPI1_MISO_PORT (GPIO_PORT_H)
#define SPI1_MISO_PIN (GPIO_PIN_15)
#define SPI1_MISO_FUNC (GPIO_FUNC_42)
#define SPI1_DEVICE_SLAVE_ID_0 0
/* SPI6 definition */
#define SPI6_UNIT (CM_SPI6)
#define SPI6_CLK (FCG1_PERIPH_SPI6)
/* SS = PI01 */
#define SPI6_SS_PORT (GPIO_PORT_I)
#define SPI6_SS_PIN (GPIO_PIN_01)
/* SCK = PH14 */
#define SPI6_SCK_PORT (GPIO_PORT_H)
#define SPI6_SCK_PIN (GPIO_PIN_14)
#define SPI6_SCK_FUNC (GPIO_FUNC_40)
/* MOSI = PI00 */
#define SPI6_MOSI_PORT (GPIO_PORT_I)
#define SPI6_MOSI_PIN (GPIO_PIN_00)
#define SPI6_MOSI_FUNC (GPIO_FUNC_41)
/* MISO = PH15 */
#define SPI6_MISO_PORT (GPIO_PORT_H)
#define SPI6_MISO_PIN (GPIO_PIN_15)
#define SPI6_MISO_FUNC (GPIO_FUNC_42)
#define SPI6_DEVICE_SLAVE_ID_0 0
static void HwSpiEnable(CM_SPI_TypeDef *SPIx)
{
/* Check if the SPI is already enabled */
if (SPI_CR1_SPE != (SPIx->CR1 & SPI_CR1_SPE)) {
SPI_Cmd(SPIx, ENABLE);
}
}
/*Init the spi sdk intetface */
static uint32 SpiSdkInit(struct SpiDriver *spi_drv)
{
NULL_PARAM_CHECK(spi_drv);
stc_spi_init_t stcSpiInit;
stc_gpio_init_t stcGpioInit;
SpiDeviceParam *dev_param = (SpiDeviceParam *)(spi_drv->driver.private_data);
#ifdef BSP_USING_SPI1
/* Configure Port */
(void)GPIO_StructInit(&stcGpioInit);
stcGpioInit.u16PinState = PIN_STAT_RST;
stcGpioInit.u16PinDir = PIN_DIR_OUT;
(void)GPIO_Init(SPI1_SS_PORT, SPI1_SS_PIN, &stcGpioInit);
GPIO_SetPins(SPI1_SS_PORT, SPI1_SS_PIN);
GPIO_SetFunc(SPI1_SCK_PORT, SPI1_SCK_PIN, SPI1_SCK_FUNC);
GPIO_SetFunc(SPI1_MOSI_PORT, SPI1_MOSI_PIN, SPI1_MOSI_FUNC);
GPIO_SetFunc(SPI1_MISO_PORT, SPI1_MISO_PIN, SPI1_MISO_FUNC);
/* Configuration SPI */
FCG_Fcg1PeriphClockCmd(SPI1_CLK, ENABLE);
SPI_StructInit(&stcSpiInit);
stcSpiInit.u32WireMode = SPI_4_WIRE;
stcSpiInit.u32TransMode = SPI_FULL_DUPLEX;
stcSpiInit.u32MasterSlave = SPI1_MASTER_SLAVE_MODE;
stcSpiInit.u32Parity = SPI_PARITY_INVD;
if (SPI_MODE_0 == dev_param->spi_master_param->spi_work_mode & 0x3) {
stcSpiInit.u32SpiMode = SPI_MD_0;
} else if (SPI_MODE_1 == dev_param->spi_master_param->spi_work_mode & 0x3) {
stcSpiInit.u32SpiMode = SPI_MD_1;
} else if (SPI_MODE_2 == dev_param->spi_master_param->spi_work_mode & 0x3) {
stcSpiInit.u32SpiMode = SPI_MD_2;
} else if (SPI_MODE_3 == dev_param->spi_master_param->spi_work_mode & 0x3) {
stcSpiInit.u32SpiMode = SPI_MD_3;
}
stcSpiInit.u32BaudRatePrescaler = SPI_BR_CLK_DIV64;
if (8 == dev_param->spi_master_param->spi_data_bit_width) {
stcSpiInit.u32DataBits = SPI_DATA_SIZE_8BIT;
} else if (7 == dev_param->spi_master_param->spi_data_bit_width) {
stcSpiInit.u32DataBits = SPI_DATA_SIZE_7BIT;
}
if (SPI_LSB == dev_param->spi_master_param->spi_work_mode & 0x4) {
stcSpiInit.u32FirstBit = SPI_FIRST_LSB;
} else if(SPI_MSB == dev_param->spi_master_param->spi_work_mode & 0x4) {
stcSpiInit.u32FirstBit = SPI_FIRST_MSB;
}
stcSpiInit.u32FrameLevel = SPI_1_FRAME;
(void)SPI_Init(SPI1_UNIT, &stcSpiInit);
SPI_Cmd(SPI1_UNIT, ENABLE);
#endif
#ifdef BSP_USING_SPI6
/* Configure Port */
(void)GPIO_StructInit(&stcGpioInit);
stcGpioInit.u16PinState = PIN_STAT_RST;
stcGpioInit.u16PinDir = PIN_DIR_OUT;
(void)GPIO_Init(SPI6_SS_PORT, SPI6_SS_PIN, &stcGpioInit);
GPIO_SetPins(SPI6_SS_PORT, SPI6_SS_PIN);
GPIO_SetFunc(SPI6_SCK_PORT, SPI6_SCK_PIN, SPI6_SCK_FUNC);
GPIO_SetFunc(SPI6_MOSI_PORT, SPI6_MOSI_PIN, SPI6_MOSI_FUNC);
GPIO_SetFunc(SPI6_MISO_PORT, SPI6_MISO_PIN, SPI6_MISO_FUNC);
/* Configuration SPI */
FCG_Fcg1PeriphClockCmd(SPI6_CLK, ENABLE);
SPI_StructInit(&stcSpiInit);
stcSpiInit.u32WireMode = SPI_4_WIRE;
stcSpiInit.u32TransMode = SPI_FULL_DUPLEX;
stcSpiInit.u32MasterSlave = SPI1_MASTER_SLAVE_MODE;
stcSpiInit.u32Parity = SPI_PARITY_INVD;
if (SPI_MODE_0 == dev_param->spi_master_param->spi_work_mode & 0x3) {
stcSpiInit.u32SpiMode = SPI_MD_0;
} else if (SPI_MODE_1 == dev_param->spi_master_param->spi_work_mode & 0x3) {
stcSpiInit.u32SpiMode = SPI_MD_1;
} else if (SPI_MODE_2 == dev_param->spi_master_param->spi_work_mode & 0x3) {
stcSpiInit.u32SpiMode = SPI_MD_2;
} else if (SPI_MODE_3 == dev_param->spi_master_param->spi_work_mode & 0x3) {
stcSpiInit.u32SpiMode = SPI_MD_3;
}
stcSpiInit.u32BaudRatePrescaler = SPI_BR_CLK_DIV64;
if (8 == dev_param->spi_master_param->spi_data_bit_width) {
stcSpiInit.u32DataBits = SPI_DATA_SIZE_8BIT;
} else if (7 == dev_param->spi_master_param->spi_data_bit_width) {
stcSpiInit.u32DataBits = SPI_DATA_SIZE_7BIT;
}
if (SPI_LSB == dev_param->spi_master_param->spi_work_mode & 0x4) {
stcSpiInit.u32FirstBit = SPI_FIRST_LSB;
} else if(SPI_MSB == dev_param->spi_master_param->spi_work_mode & 0x4) {
stcSpiInit.u32FirstBit = SPI_FIRST_MSB;
}
stcSpiInit.u32FrameLevel = SPI_1_FRAME;
(void)SPI_Init(SPI6_UNIT, &stcSpiInit);
SPI_Cmd(SPI6_UNIT, ENABLE);
#endif
return EOK;
}
static uint32 SpiSdkCfg(struct SpiDriver *spi_drv, struct SpiMasterParam *spi_param)
{
NULL_PARAM_CHECK(spi_drv);
NULL_PARAM_CHECK(spi_param);
SpiDeviceParam *dev_param = (SpiDeviceParam *)(spi_drv->driver.private_data);
dev_param->spi_master_param = spi_param;
dev_param->spi_master_param->spi_work_mode = dev_param->spi_master_param->spi_work_mode & SPI_MODE_MASK;
return EOK;
}
/*Configure the spi device param, make sure struct (configure_info->private_data) = (SpiMasterParam)*/
static uint32 SpiDrvConfigure(void *drv, struct BusConfigureInfo *configure_info)
{
NULL_PARAM_CHECK(drv);
NULL_PARAM_CHECK(configure_info);
x_err_t ret = EOK;
struct SpiDriver *spi_drv = (struct SpiDriver *)drv;
struct SpiMasterParam *spi_param;
switch (configure_info->configure_cmd)
{
case OPE_INT:
ret = SpiSdkInit(spi_drv);
break;
case OPE_CFG:
spi_param = (struct SpiMasterParam *)configure_info->private_data;
ret = SpiSdkCfg(spi_drv, spi_param);
break;
default:
break;
}
return ret;
}
static uint32 SpiWriteData(struct SpiHardwareDevice *spi_dev, struct SpiDataStandard *spi_datacfg)
{
SpiDeviceParam *dev_param = (SpiDeviceParam *)(spi_dev->haldev.private_data);
uint8 cs_gpio_pin = dev_param->spi_slave_param->spi_cs_gpio_pin;
uint8 cs_gpio_port = dev_param->spi_slave_param->spi_cs_gpio_port;
CM_SPI_TypeDef *spi = spi_dev->haldev.owner_bus->private_data;
int i = 0;
uint32 ret = EOK;
int32 spi_write_status = 0;
while (NONE != spi_datacfg) {
if (spi_datacfg->spi_chip_select) {
GPIO_ResetPins(cs_gpio_port, cs_gpio_pin);
}
if (spi_datacfg->length) {
uint8 *tx_buff = x_malloc(spi_datacfg->length);
if ((spi_datacfg->tx_buff) && (tx_buff)) {
memset(tx_buff, 0, spi_datacfg->length);
for (i = 0; i < spi_datacfg->length; i++) {
tx_buff[i] = ((uint8 *)spi_datacfg->tx_buff)[i];
}
HwSpiEnable(spi);
spi_write_status = SPI_Trans(spi, tx_buff, spi_datacfg->length, 1000);
while (RESET != SPI_GetStatus(spi, SPI_FLAG_IDLE));
if (LL_OK == spi_write_status) {
ret = ERROR;
}
}
if (tx_buff) {
x_free(tx_buff);
}
SPI_ClearStatus(spi, SPI_FLAG_CLR_ALL | SPI_FLAG_RX_BUF_FULL);
}
if (spi_datacfg->spi_cs_release) {
GPIO_SetPins(cs_gpio_port, cs_gpio_pin);
}
spi_datacfg = spi_datacfg->next;
}
return ret;
}
static uint32 SpiReadData(struct SpiHardwareDevice *spi_dev, struct SpiDataStandard *spi_datacfg)
{
SpiDeviceParam *dev_param = (SpiDeviceParam *)(spi_dev->haldev.private_data);
uint8 cs_gpio_pin = dev_param->spi_slave_param->spi_cs_gpio_pin;
uint8 cs_gpio_port = dev_param->spi_slave_param->spi_cs_gpio_port;
CM_SPI_TypeDef *spi = spi_dev->haldev.owner_bus->private_data;
int i = 0;
int32 spi_read_status = 0;
uint32 spi_read_length = 0;
while (NONE != spi_datacfg) {
if (spi_datacfg->spi_chip_select) {
GPIO_ResetPins(cs_gpio_port, cs_gpio_pin);
}
if (spi_datacfg->length) {
uint8_t *rx_buff = x_malloc(spi_datacfg->length);
if ((spi_datacfg->rx_buff) && (rx_buff)) {
memset(rx_buff, 0xFF, spi_datacfg->length);
HwSpiEnable(spi);
spi_read_status = SPI_Receive(spi, rx_buff, spi_datacfg->length, 1000);
while (RESET != SPI_GetStatus(spi, SPI_FLAG_IDLE));
if (LL_OK == spi_read_status) {
for (i = 0; i < spi_datacfg->length; i++) {
((uint8_t *)spi_datacfg->rx_buff)[i] = rx_buff[i];
}
}
}
if (rx_buff) {
x_free(rx_buff);
}
SPI_ClearStatus(spi, SPI_FLAG_CLR_ALL | SPI_FLAG_RX_BUF_FULL);
}
if (spi_datacfg->spi_cs_release) {
GPIO_SetPins(cs_gpio_port, cs_gpio_pin);
}
spi_read_length += spi_datacfg->length;
spi_datacfg = spi_datacfg->next;
}
return spi_read_length;
}
/*manage the spi device operations*/
static const struct SpiDevDone spi_dev_done =
{
.dev_open = NONE,
.dev_close = NONE,
.dev_write = SpiWriteData,
.dev_read = SpiReadData,
};
static int BoardSpiBusInit(struct SpiBus *spi_bus, struct SpiDriver *spi_driver, const char *bus_name, const char *drv_name)
{
x_err_t ret = EOK;
/*Init the spi bus */
ret = SpiBusInit(spi_bus, bus_name);
if (EOK != ret) {
KPrintf("Board_Spi_init SpiBusInit error %d\n", ret);
return ERROR;
}
/*Init the spi driver*/
ret = SpiDriverInit(spi_driver, drv_name);
if (EOK != ret) {
KPrintf("Board_Spi_init SpiDriverInit error %d\n", ret);
return ERROR;
}
/*Attach the spi driver to the spi bus*/
ret = SpiDriverAttachToBus(drv_name, bus_name);
if (EOK != ret) {
KPrintf("Board_Spi_init SpiDriverAttachToBus error %d\n", ret);
return ERROR;
}
return ret;
}
/*Attach the spi device to the spi bus*/
static int BoardSpiDevBend(void)
{
x_err_t ret = EOK;
#ifdef SPI_1_DEVICE_NAME_0
static struct SpiHardwareDevice spi1_device0;
memset(&spi1_device0, 0, sizeof(struct SpiHardwareDevice));
static struct SpiSlaveParam spi1_slaveparam0;
memset(&spi1_slaveparam0, 0, sizeof(struct SpiSlaveParam));
spi1_slaveparam0.spi_slave_id = SPI1_DEVICE_SLAVE_ID_0;
spi1_slaveparam0.spi_cs_gpio_pin = SPI1_SS_PIN;
spi1_slaveparam0.spi_cs_gpio_port = SPI1_SS_PORT;
spi1_device0.spi_param.spi_slave_param = &spi1_slaveparam0;
spi1_device0.spi_dev_done = &(spi_dev_done);
ret = SpiDeviceRegister(&spi1_device0, (void *)(&spi1_device0.spi_param), SPI_1_DEVICE_NAME_0);
if (EOK != ret) {
KPrintf("BoardSpiDevBend SpiDeviceRegister device %s error %d\n", SPI_1_DEVICE_NAME_0, ret);
return ERROR;
}
ret = SpiDeviceAttachToBus(SPI_1_DEVICE_NAME_0, SPI_BUS_NAME_1);
if (EOK != ret) {
KPrintf("BoardSpiDevBend SpiDeviceAttachToBus device %s error %d\n", SPI_1_DEVICE_NAME_0, ret);
return ERROR;
}
#endif
#ifdef SPI_6_DEVICE_NAME_0
static struct SpiHardwareDevice spi6_device0;
memset(&spi6_device0, 0, sizeof(struct SpiHardwareDevice));
static struct SpiSlaveParam spi6_slaveparam0;
memset(&spi6_slaveparam0, 0, sizeof(struct SpiSlaveParam));
spi6_slaveparam0.spi_slave_id = SPI1_DEVICE_SLAVE_ID_0;
spi6_slaveparam0.spi_cs_gpio_pin = SPI6_SS_PIN;
spi6_slaveparam0.spi_cs_gpio_port = SPI6_SS_PORT;
spi6_device0.spi_param.spi_slave_param = &spi6_slaveparam0;
spi6_device0.spi_dev_done = &(spi_dev_done);
ret = SpiDeviceRegister(&spi6_device0, (void *)(&spi6_device0.spi_param), SPI_6_DEVICE_NAME_0);
if (EOK != ret) {
KPrintf("BoardSpiDevBend SpiDeviceRegister device %s error %d\n", SPI_6_DEVICE_NAME_0, ret);
return ERROR;
}
ret = SpiDeviceAttachToBus(SPI_6_DEVICE_NAME_0, SPI_BUS_NAME_6);
if (EOK != ret) {
KPrintf("BoardSpiDevBend SpiDeviceAttachToBus device %s error %d\n", SPI_6_DEVICE_NAME_0, ret);
return ERROR;
}
#endif
return ret;
}
int HwSpiInit(void)
{
x_err_t ret = EOK;
#ifdef BSP_USING_SPI1
static struct SpiBus spi1_bus;
memset(&spi1_bus, 0, sizeof(struct SpiBus));
static struct SpiDriver spi1_driver;
memset(&spi1_driver, 0, sizeof(struct SpiDriver));
spi1_bus.private_data = SPI1_UNIT;
spi1_driver.configure = SpiDrvConfigure;
ret = BoardSpiBusInit(&spi1_bus, &spi1_driver, SPI_BUS_NAME_1, SPI_1_DRV_NAME);
if (EOK != ret) {
KPrintf("BoardSpiBusInit error ret %u\n", ret);
return ERROR;
}
ret = BoardSpiDevBend();
if (EOK != ret) {
KPrintf("BoardSpiDevBend error ret %u\n", ret);
return ERROR;
}
#endif
#ifdef BSP_USING_SPI6
static struct SpiBus spi6_bus;
memset(&spi6_bus, 0, sizeof(struct SpiBus));
static struct SpiDriver spi6_driver;
memset(&spi6_driver, 0, sizeof(struct SpiDriver));
spi6_bus.private_data = SPI6_UNIT;
spi6_driver.configure = SpiDrvConfigure;
ret = BoardSpiBusInit(&spi6_bus, &spi6_driver, SPI_BUS_NAME_6, SPI_6_DRV_NAME);
if (EOK != ret) {
KPrintf("BoardSpiBusInit error ret %u\n", ret);
return ERROR;
}
ret = BoardSpiDevBend();
if (EOK != ret) {
KPrintf("BoardSpiDevBend error ret %u\n", ret);
return ERROR;
}
#endif
return ret;
}
/*Just for lora test*/
static struct Bus *bus;
static struct HardwareDev *dev;
static struct Driver *drv;
static uint32 TestSpiLoraOpen(void)
{
NULL_PARAM_CHECK(drv);
KPrintf("SpiLoraOpen start\n");
x_err_t ret = EOK;
struct BusConfigureInfo configure_info;
struct SpiMasterParam spi_master_param;
spi_master_param.spi_data_bit_width = 8;
spi_master_param.spi_work_mode = SPI_MODE_0 | SPI_MSB;
configure_info.configure_cmd = OPE_CFG;
configure_info.private_data = (void *)&spi_master_param;
ret = BusDrvConfigure(drv, &configure_info);
if (ret) {
KPrintf("spi drv OPE_CFG error drv %8p cfg %8p\n", drv, &spi_master_param);
return ERROR;
}
configure_info.configure_cmd = OPE_INT;
ret = BusDrvConfigure(drv, &configure_info);
if (ret) {
KPrintf("spi drv OPE_INT error drv %8p\n", drv);
return ERROR;
}
return ret;
}
static void TestSpiRead(void)
{
struct BusBlockWriteParam write_param;
struct BusBlockReadParam read_param;
uint8 write_addr = 0x06 & 0x7F;
uint8 read_data = 0;
BusDevOpen(dev);
write_param.buffer = (void *)&write_addr;
write_param.size = 1;
BusDevWriteData(dev, &write_param);
read_param.buffer = (void *)&read_data;
read_param.size = 1;
BusDevReadData(dev, &read_param);
BusDevClose(dev);
KPrintf("read data from lora 0x06 register, receive data 0x%x\n", read_data);
}
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN),
TestSpiRead, TestSpiRead, read data from lora register);
void TestLoraOpen(void)
{
x_err_t ret = EOK;
bus = BusFind(SPI_BUS_NAME_1);
dev = BusFindDevice(bus, SPI_1_DEVICE_NAME_0);
drv = BusFindDriver(bus, SPI_1_DRV_NAME);
bus->match(drv, dev);
ret = TestSpiLoraOpen();
if (EOK != ret) {
KPrintf("LoRa init failed\n");
return;
}
KPrintf("LoRa init succeed\n");
return;
}
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN),
TestLoraOpen, TestLoraOpen, open lora device and read parameters);
@@ -0,0 +1,5 @@
ifeq ($(CONFIG_RESOURCES_SPI_LORA),y)
SRC_DIR := sx12xx
endif
include $(KERNEL_ROOT)/compiler.mk
@@ -0,0 +1,3 @@
SRC_DIR := src
include $(KERNEL_ROOT)/compiler.mk
@@ -0,0 +1,51 @@
/*
* Copyright (c) 2020 AIIT XUOS Lab
* XiUOS is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
/**
* @file spi_lora_sx12xx.h
* @brief define spi lora driver function
* @version 2.0
* @author AIIT XUOS Lab
* @date 2022-10-31
*/
#ifndef SPI_LORA_SX12XX_H
#define SPI_LORA_SX12XX_H
#include <connect_spi_lora.h>
#ifdef __cplusplus
extern "C" {
#endif
uint8_t SX1276ReadDio0(void);
uint8_t SX1276ReadDio1(void);
uint8_t SX1276ReadDio2(void);
uint8_t SX1276ReadDio3(void);
uint8_t SX1276ReadDio4(void);
uint8_t SX1276ReadDio5(void);
void SX1276Write(uint8_t addr, uint8_t data);
void SX1276Read(uint8_t addr, uint8_t *data);
void SX1276WriteBuffer(uint8_t addr, uint8_t *buffer, uint8_t size);
void SX1276ReadBuffer(uint8_t addr, uint8_t *buffer, uint8_t size);
void SX1276WriteFifo(uint8_t *buffer, uint8_t size);
void SX1276ReadFifo(uint8_t *buffer, uint8_t size);
void SX1276SetReset(uint8_t state);
uint8_t Sx1276SpiCheck(void);
void SX1276WriteRxTx(uint8_t txEnable);
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,3 @@
SRC_DIR := radio
include $(KERNEL_ROOT)/compiler.mk
@@ -0,0 +1,3 @@
SRC_FILES := radio.c sx1276-Fsk.c sx1276-FskMisc.c sx1276-LoRa.c sx1276-LoRaMisc.c sx1276.c
include $(KERNEL_ROOT)/compiler.mk
@@ -0,0 +1,96 @@
/*
* THE FOLLOWING FIRMWARE IS PROVIDED: (1) "AS IS" WITH NO WARRANTY; AND
* (2)TO ENABLE ACCESS TO CODING INFORMATION TO GUIDE AND FACILITATE CUSTOMER.
* CONSEQUENTLY, SEMTECH SHALL NOT BE HELD LIABLE FOR ANY DIRECT, INDIRECT OR
* CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE CONTENT
* OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING INFORMATION
* CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*
* Copyright (C) SEMTECH S.A.
*/
/*!
* \file platform.h
* \brief
*
* \version 1.0
* \date Nov 21 2012
* \author Miguel Luis
*/
/*************************************************
File name: platform.h
Description: support aiit board configure and register function
History:
1. Date: 2021-04-25
Author: AIIT XUOS Lab
Modification:
1. replace original macro and basic date type with AIIT XUOS Lab's own defination
*************************************************/
#ifndef __PLATFORM_H__
#define __PLATFORM_H__
#ifndef __GNUC__
#define inline
#endif
/*!
* Platform definition
*/
#define Bleeper 3
#define SX1243ska 2
#define SX12xxEiger 1
#define SX12000DVK 0
/*!
* Platform choice. Please uncoment the PLATFORM define and choose your platform
* or add/change the PLATFORM definition on the compiler Defines option
*/
#define PLATFORM SX12xxEiger
#if( PLATFORM == SX12xxEiger )
/*!
* Radio choice. Please uncomment the wanted radio and comment the others
* or add/change wanted radio definition on the compiler Defines option
*/
//#define USE_SX1232_RADIO
//#define USE_SX1272_RADIO
#define USE_SX1276_RADIO
//#define USE_SX1243_RADIO
/*!
* Module choice. There are three existing module with the SX1276.
* Please set the connected module to the value 1 and set the others to 0
*/
#ifdef USE_SX1276_RADIO
#define MODULE_SX1276RF1IAS 0
#define MODULE_SX1276RF1JAS 0
#define MODULE_SX1276RF1KAS 1
#endif
#include <spi_lora_sx12xx.h>
#define USE_UART 0
#elif( PLATFORM == SX12000DVK )
/*!
* Radio choice. Please uncomment the wanted radio and comment the others
* or add/change wanted radio definition on the compiler Defines option
*/
//#define USE_SX1232_RADIO
#define USE_SX1272_RADIO
//#define USE_SX1276_RADIO
//#define USE_SX1243_RADIO
#include "sx1200dvk/sx1200dvk.h"
#elif( PLATFORM == SX1243ska )
#elif( PLATFORM == Bleeper )
#define USE_SX1272_RADIO
#include "bleeper/bleeper.h"
#define USE_UART 0
#else
#error "Missing define: Platform (ie. SX12xxEiger)"
#endif
#endif // __PLATFORM_H__
@@ -0,0 +1,75 @@
/*
* THE FOLLOWING FIRMWARE IS PROVIDED: (1) "AS IS" WITH NO WARRANTY; AND
* (2)TO ENABLE ACCESS TO CODING INFORMATION TO GUIDE AND FACILITATE CUSTOMER.
* CONSEQUENTLY, SEMTECH SHALL NOT BE HELD LIABLE FOR ANY DIRECT, INDIRECT OR
* CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE CONTENT
* OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING INFORMATION
* CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*
* Copyright (C) SEMTECH S.A.
*/
/*!
* \file radio.c
* \brief Generic radio driver ( radio abstraction )
*
* \version 2.0.0
* \date Nov 21 2012
* \author Miguel Luis
*
* Last modified by Gregory Cristian on Apr 25 2013
*/
/*************************************************
File name: radio.c
Description: support aiit board configure and register function
History:
1. Date: 2021-04-25
Author: AIIT XUOS Lab
Modification:
1. replace original macro and basic date type with AIIT XUOS Lab's own defination
*************************************************/
#include <stdint.h>
#include "platform.h"
#include "radio.h"
#if defined( USE_SX1232_RADIO )
#include "sx1232.h"
#elif defined( USE_SX1272_RADIO )
#include "sx1272.h"
#elif defined( USE_SX1276_RADIO )
#include "sx1276.h"
#else
#error "Missing define: USE_XXXXXX_RADIO (ie. USE_SX1272_RADIO)"
#endif
tRadioDriver RadioDriver;
tRadioDriver* RadioDriverInit( void )
{
#if defined( USE_SX1232_RADIO )
RadioDriver.Init = SX1232Init;
RadioDriver.Reset = SX1232Reset;
RadioDriver.StartRx = SX1232StartRx;
RadioDriver.GetRxPacket = SX1232GetRxPacket;
RadioDriver.SetTxPacket = SX1232SetTxPacket;
RadioDriver.Process = SX1232Process;
#elif defined( USE_SX1272_RADIO )
RadioDriver.Init = SX1272Init;
RadioDriver.Reset = SX1272Reset;
RadioDriver.StartRx = SX1272StartRx;
RadioDriver.GetRxPacket = SX1272GetRxPacket;
RadioDriver.SetTxPacket = SX1272SetTxPacket;
RadioDriver.Process = SX1272Process;
#elif defined( USE_SX1276_RADIO )
RadioDriver.Init = SX1276Init;
RadioDriver.Reset = SX1276Reset;
RadioDriver.StartRx = SX1276StartRx;
RadioDriver.GetRxPacket = SX1276GetRxPacket;
RadioDriver.SetTxPacket = SX1276SetTxPacket;
RadioDriver.Process = SX1276Process;
RadioDriver.ChannelEmpty = SX1276ChannelEmpty;
#else
#error "Missing define: USE_XXXXXX_RADIO (ie. USE_SX1272_RADIO)"
#endif
return &RadioDriver;
}
@@ -0,0 +1,77 @@
/*
* THE FOLLOWING FIRMWARE IS PROVIDED: (1) "AS IS" WITH NO WARRANTY; AND
* (2)TO ENABLE ACCESS TO CODING INFORMATION TO GUIDE AND FACILITATE CUSTOMER.
* CONSEQUENTLY, SEMTECH SHALL NOT BE HELD LIABLE FOR ANY DIRECT, INDIRECT OR
* CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE CONTENT
* OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING INFORMATION
* CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*
* Copyright (C) SEMTECH S.A.
*/
/*!
* \file radio.h
* \brief Generic radio driver ( radio abstraction )
*
* \version 2.0.B2
* \date Nov 21 2012
* \author Miguel Luis
*
* Last modified by Gregory Cristian on Apr 25 2013
*/
/*************************************************
File name: radio.h
Description: support aiit board configure and register function
History:
1. Date: 2021-04-25
Author: AIIT XUOS Lab
Modification:
1. replace original macro and basic date type with AIIT XUOS Lab's own defination
*************************************************/
#ifndef __RADIO_H__
#define __RADIO_H__
/*!
* SX1272 and SX1276 General parameters definition
*/
#define LORA 1 // [0: OFF, 1: ON]
/*!
* RF process function return codes
*/
typedef enum
{
RF_IDLE,
RF_BUSY,
RF_RX_DONE,
RF_RX_TIMEOUT,
RF_TX_DONE,
RF_TX_TIMEOUT,
RF_LEN_ERROR,
RF_CHANNEL_EMPTY,
RF_CHANNEL_ACTIVITY_DETECTED,
}tRFProcessReturnCodes;
/*!
* Radio driver structure defining the different function pointers
*/
typedef struct sRadioDriver
{
void ( *Init )( void );
void ( *Reset )( void );
void ( *StartRx )( void );
void ( *GetRxPacket )( void *buffer, uint16_t *size );
void ( *SetTxPacket )( const void *buffer, uint16_t size );
uint32_t ( *Process )( void );
uint32_t ( *ChannelEmpty )(void );
}tRadioDriver;
/*!
* \brief Initializes the RadioDriver structure with specific radio
* functions.
*
* \retval radioDriver Pointer to the radio driver variable
*/
tRadioDriver* RadioDriverInit( void );
#endif // __RADIO_H__
@@ -0,0 +1,616 @@
/*
* THE FOLLOWING FIRMWARE IS PROVIDED: (1) "AS IS" WITH NO WARRANTY; AND
* (2)TO ENABLE ACCESS TO CODING INFORMATION TO GUIDE AND FACILITATE CUSTOMER.
* CONSEQUENTLY, SEMTECH SHALL NOT BE HELD LIABLE FOR ANY DIRECT, INDIRECT OR
* CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE CONTENT
* OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING INFORMATION
* CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*
* Copyright (C) SEMTECH S.A.
*/
/*!
* \file sx1276.c
* \brief SX1276 RF chip driver
*
* \version 2.0.0
* \date May 6 2013
* \author Gregory Cristian
*
* Last modified by Miguel Luis on Jun 19 2013
*/
/*************************************************
File name: sx1276-Fsk.c
Description: support aiit board configure and register function
History:
1. Date: 2021-04-25
Author: AIIT XUOS Lab
Modification:
1. replace original macro and basic date type with AIIT XUOS Lab's own defination
*************************************************/
#include <string.h>
#include <math.h>
#include "platform.h"
#if defined( USE_SX1276_RADIO )
#include "radio.h"
#include "sx1276-Hal.h"
#include "sx1276.h"
#include "sx1276-FskMisc.h"
#include "sx1276-Fsk.h"
// Default settings
tFskSettings FskSettings =
{
870000000, // RFFrequency
9600, // Bitrate
50000, // Fdev
20, // Power
100000, // RxBw
150000, // RxBwAfc
true, // CrcOn
true, // AfcOn
255 // PayloadLength (set payload size to the maximum for variable mode, else set the exact payload length)
};
/*!
* SX1276 FSK registers variable
*/
tSX1276* SX1276;
/*!
* Local RF buffer for communication support
*/
static uint8_t RFBuffer[RF_BUFFER_SIZE];
/*!
* Chunk size of data write in buffer
*/
static uint8_t DataChunkSize = 32;
/*!
* RF state machine variable
*/
static uint8_t RFState = RF_STATE_IDLE;
/*!
* Rx management support variables
*/
/*!
* PacketTimeout holds the RF packet timeout
* SyncSize = [0..8]
* VariableSize = [0;1]
* AddressSize = [0;1]
* PayloadSize = [0..RF_BUFFER_SIZE]
* CrcSize = [0;2]
* PacketTimeout = ( ( 8 * ( VariableSize + AddressSize + PayloadSize + CrcSize ) / BR ) * 1000.0 ) + 1
* Computed timeout is in miliseconds
*/
static uint32_t PacketTimeout;
/*!
* Preamble2SyncTimeout
* Preamble2SyncTimeout = ( ( 8 * ( PremableSize + SyncSize ) / RFBitrate ) * 1000.0 ) + 1
* Computed timeout is in miliseconds
*/
static uint32_t Preamble2SyncTimeout;
static bool PreambleDetected = false;
static bool SyncWordDetected = false;
static bool PacketDetected = false;
static uint16_t RxPacketSize = 0;
static uint8_t RxBytesRead = 0;
static uint8_t TxBytesSent = 0;
static double RxPacketRssiValue;
static uint32_t RxPacketAfcValue;
static uint8_t RxGain = 1;
static uint32_t RxTimeoutTimer = 0;
static uint32_t Preamble2SyncTimer = 0;
/*!
* Tx management support variables
*/
static uint16_t TxPacketSize = 0;
static uint32_t TxTimeoutTimer = 0;
void SX1276FskInit( void )
{
RFState = RF_STATE_IDLE;
SX1276FskSetDefaults( );
SX1276ReadBuffer( REG_OPMODE, SX1276Regs + 1, 0x70 - 1 );
// Set the device in FSK mode and Sleep Mode
SX1276->RegOpMode = RF_OPMODE_MODULATIONTYPE_FSK | RF_OPMODE_SLEEP;
SX1276Write( REG_OPMODE, SX1276->RegOpMode );
SX1276->RegPaRamp = RF_PARAMP_MODULATIONSHAPING_01;
SX1276Write( REG_PARAMP, SX1276->RegPaRamp );
SX1276->RegLna = RF_LNA_GAIN_G1;
SX1276Write( REG_LNA, SX1276->RegLna );
if( FskSettings.AfcOn == true )
{
SX1276->RegRxConfig = RF_RXCONFIG_RESTARTRXONCOLLISION_OFF | RF_RXCONFIG_AFCAUTO_ON |
RF_RXCONFIG_AGCAUTO_ON | RF_RXCONFIG_RXTRIGER_PREAMBLEDETECT;
}
else
{
SX1276->RegRxConfig = RF_RXCONFIG_RESTARTRXONCOLLISION_OFF | RF_RXCONFIG_AFCAUTO_OFF |
RF_RXCONFIG_AGCAUTO_ON | RF_RXCONFIG_RXTRIGER_PREAMBLEDETECT;
}
SX1276->RegPreambleLsb = 8;
SX1276->RegPreambleDetect = RF_PREAMBLEDETECT_DETECTOR_ON | RF_PREAMBLEDETECT_DETECTORSIZE_2 |
RF_PREAMBLEDETECT_DETECTORTOL_10;
SX1276->RegRssiThresh = 0xFF;
SX1276->RegSyncConfig = RF_SYNCCONFIG_AUTORESTARTRXMODE_WAITPLL_ON | RF_SYNCCONFIG_PREAMBLEPOLARITY_AA |
RF_SYNCCONFIG_SYNC_ON |
RF_SYNCCONFIG_SYNCSIZE_4;
SX1276->RegSyncValue1 = 0x69;
SX1276->RegSyncValue2 = 0x81;
SX1276->RegSyncValue3 = 0x7E;
SX1276->RegSyncValue4 = 0x96;
SX1276->RegPacketConfig1 = RF_PACKETCONFIG1_PACKETFORMAT_VARIABLE | RF_PACKETCONFIG1_DCFREE_OFF |
( FskSettings.CrcOn << 4 ) | RF_PACKETCONFIG1_CRCAUTOCLEAR_ON |
RF_PACKETCONFIG1_ADDRSFILTERING_OFF | RF_PACKETCONFIG1_CRCWHITENINGTYPE_CCITT;
SX1276FskGetPacketCrcOn( ); // Update CrcOn on FskSettings
SX1276->RegPayloadLength = FskSettings.PayloadLength;
// we can now update the registers with our configuration
SX1276WriteBuffer( REG_OPMODE, SX1276Regs + 1, 0x70 - 1 );
// then we need to set the RF settings
SX1276FskSetRFFrequency( FskSettings.RFFrequency );
SX1276FskSetBitrate( FskSettings.Bitrate );
SX1276FskSetFdev( FskSettings.Fdev );
SX1276FskSetDccBw( &SX1276->RegRxBw, 0, FskSettings.RxBw );
SX1276FskSetDccBw( &SX1276->RegAfcBw, 0, FskSettings.RxBwAfc );
SX1276FskSetRssiOffset( 0 );
#if( ( MODULE_SX1276RF1IAS == 1 ) || ( MODULE_SX1276RF1KAS == 1 ) )
if( FskSettings.RFFrequency > 860000000 )
{
SX1276FskSetPAOutput( RF_PACONFIG_PASELECT_RFO );
SX1276FskSetPa20dBm( false );
FskSettings.Power = 14;
SX1276FskSetRFPower( FskSettings.Power );
}
else
{
SX1276FskSetPAOutput( RF_PACONFIG_PASELECT_PABOOST );
SX1276FskSetPa20dBm( true );
FskSettings.Power = 20;
SX1276FskSetRFPower( FskSettings.Power );
}
#elif( MODULE_SX1276RF1JAS == 1 )
if( FskSettings.RFFrequency > 860000000 )
{
SX1276FskSetPAOutput( RF_PACONFIG_PASELECT_PABOOST );
SX1276FskSetPa20dBm( true );
FskSettings.Power = 20;
SX1276FskSetRFPower( FskSettings.Power );
}
else
{
SX1276FskSetPAOutput( RF_PACONFIG_PASELECT_RFO );
SX1276FskSetPa20dBm( false );
FskSettings.Power = 14;
SX1276FskSetRFPower( FskSettings.Power );
}
#endif
SX1276FskSetOpMode( RF_OPMODE_STANDBY );
// Calibrate the HF
SX1276FskRxCalibrate( );
}
void SX1276FskSetDefaults( void )
{
// REMARK: See SX1276 datasheet for modified default values.
SX1276Read( REG_VERSION, &SX1276->RegVersion );
}
void SX1276FskSetOpMode( uint8_t opMode )
{
static uint8_t opModePrev = RF_OPMODE_STANDBY;
static bool antennaSwitchTxOnPrev = true;
bool antennaSwitchTxOn = false;
opModePrev = SX1276->RegOpMode & ~RF_OPMODE_MASK;
if( opMode != opModePrev )
{
if( opMode == RF_OPMODE_TRANSMITTER )
{
antennaSwitchTxOn = true;
}
else
{
antennaSwitchTxOn = false;
}
if( antennaSwitchTxOn != antennaSwitchTxOnPrev )
{
antennaSwitchTxOnPrev = antennaSwitchTxOn;
RXTX( antennaSwitchTxOn ); // Antenna switch control
}
SX1276->RegOpMode = ( SX1276->RegOpMode & RF_OPMODE_MASK ) | opMode;
SX1276Write( REG_OPMODE, SX1276->RegOpMode );
}
}
uint8_t SX1276FskGetOpMode( void )
{
SX1276Read( REG_OPMODE, &SX1276->RegOpMode );
return SX1276->RegOpMode & ~RF_OPMODE_MASK;
}
int32_t SX1276FskReadFei( void )
{
SX1276ReadBuffer( REG_FEIMSB, &SX1276->RegFeiMsb, 2 ); // Reads the FEI value
return ( int32_t )( double )( ( ( uint16_t )SX1276->RegFeiMsb << 8 ) | ( uint16_t )SX1276->RegFeiLsb ) * ( double )FREQ_STEP;
}
int32_t SX1276FskReadAfc( void )
{
SX1276ReadBuffer( REG_AFCMSB, &SX1276->RegAfcMsb, 2 ); // Reads the AFC value
return ( int32_t )( double )( ( ( uint16_t )SX1276->RegAfcMsb << 8 ) | ( uint16_t )SX1276->RegAfcLsb ) * ( double )FREQ_STEP;
}
uint8_t SX1276FskReadRxGain( void )
{
SX1276Read( REG_LNA, &SX1276->RegLna );
return( SX1276->RegLna >> 5 ) & 0x07;
}
double SX1276FskReadRssi( void )
{
SX1276Read( REG_RSSIVALUE, &SX1276->RegRssiValue ); // Reads the RSSI value
return -( double )( ( double )SX1276->RegRssiValue / 2.0 );
}
uint8_t SX1276FskGetPacketRxGain( void )
{
return RxGain;
}
double SX1276FskGetPacketRssi( void )
{
return RxPacketRssiValue;
}
uint32_t SX1276FskGetPacketAfc( void )
{
return RxPacketAfcValue;
}
void SX1276FskStartRx( void )
{
SX1276FskSetRFState( RF_STATE_RX_INIT );
}
void SX1276FskGetRxPacket( void *buffer, uint16_t *size )
{
*size = RxPacketSize;
RxPacketSize = 0;
memcpy( ( void * )buffer, ( void * )RFBuffer, ( size_t )*size );
}
void SX1276FskSetTxPacket( const void *buffer, uint16_t size )
{
TxPacketSize = size;
memcpy( ( void * )RFBuffer, buffer, ( size_t )TxPacketSize );
RFState = RF_STATE_TX_INIT;
}
// Remark: SX1276 must be fully initialized before calling this function
uint16_t SX1276FskGetPacketPayloadSize( void )
{
uint16_t syncSize;
uint16_t variableSize;
uint16_t addressSize;
uint16_t payloadSize;
uint16_t crcSize;
syncSize = ( SX1276->RegSyncConfig & 0x07 ) + 1;
variableSize = ( ( SX1276->RegPacketConfig1 & 0x80 ) == 0x80 ) ? 1 : 0;
addressSize = ( ( SX1276->RegPacketConfig1 & 0x06 ) != 0x00 ) ? 1 : 0;
payloadSize = SX1276->RegPayloadLength;
crcSize = ( ( SX1276->RegPacketConfig1 & 0x10 ) == 0x10 ) ? 2 : 0;
return syncSize + variableSize + addressSize + payloadSize + crcSize;
}
// Remark: SX1276 must be fully initialized before calling this function
uint16_t SX1276FskGetPacketHeaderSize( void )
{
uint16_t preambleSize;
uint16_t syncSize;
preambleSize = ( ( uint16_t )SX1276->RegPreambleMsb << 8 ) | ( uint16_t )SX1276->RegPreambleLsb;
syncSize = ( SX1276->RegSyncConfig & 0x07 ) + 1;
return preambleSize + syncSize;
}
uint8_t SX1276FskGetRFState( void )
{
return RFState;
}
void SX1276FskSetRFState( uint8_t state )
{
RFState = state;
}
uint32_t SX1276FskProcess( void )
{
uint32_t result = RF_BUSY;
switch( RFState )
{
case RF_STATE_IDLE:
break;
// Rx management
case RF_STATE_RX_INIT:
// DIO mapping setup
if( ( SX1276->RegPacketConfig1 & RF_PACKETCONFIG1_CRC_ON ) == RF_PACKETCONFIG1_CRC_ON )
{
// CrcOk, FifoLevel, SyncAddr, FifoEmpty
SX1276->RegDioMapping1 = RF_DIOMAPPING1_DIO0_01 | RF_DIOMAPPING1_DIO1_00 | RF_DIOMAPPING1_DIO2_11 | RF_DIOMAPPING1_DIO3_00;
}
else
{
// PayloadReady, FifoLevel, SyncAddr, FifoEmpty
SX1276->RegDioMapping1 = RF_DIOMAPPING1_DIO0_00 | RF_DIOMAPPING1_DIO1_00 | RF_DIOMAPPING1_DIO2_11 | RF_DIOMAPPING1_DIO3_00;
}
// Preamble, Data
SX1276->RegDioMapping2 = RF_DIOMAPPING2_DIO4_11 | RF_DIOMAPPING2_DIO5_10 | RF_DIOMAPPING2_MAP_PREAMBLEDETECT;
SX1276WriteBuffer( REG_DIOMAPPING1, &SX1276->RegDioMapping1, 2 );
SX1276FskSetOpMode( RF_OPMODE_RECEIVER );
memset( RFBuffer, 0, ( size_t )RF_BUFFER_SIZE );
PacketTimeout = ( uint16_t )( round( ( 8.0 * ( ( double )SX1276FskGetPacketPayloadSize( ) ) / ( double )FskSettings.Bitrate ) * 1000.0 ) + 1.0 );
PacketTimeout = PacketTimeout + ( PacketTimeout >> 1 ); // Set the Packet timeout as 1.5 times the full payload transmission time
Preamble2SyncTimeout = PacketTimeout;
Preamble2SyncTimer = RxTimeoutTimer = GET_TICK_COUNT( );
SX1276->RegFifoThresh = RF_FIFOTHRESH_TXSTARTCONDITION_FIFONOTEMPTY | 0x20; // 32 bytes of data
SX1276Write( REG_FIFOTHRESH, SX1276->RegFifoThresh );
PreambleDetected = false;
SyncWordDetected = false;
PacketDetected = false;
RxBytesRead = 0;
RxPacketSize = 0;
RFState = RF_STATE_RX_SYNC;
break;
case RF_STATE_RX_SYNC:
if( ( DIO4 == 1 ) && ( PreambleDetected == false ) )// Preamble
{
PreambleDetected = true;
Preamble2SyncTimer = GET_TICK_COUNT( );
}
if( ( DIO2 == 1 ) && ( PreambleDetected == true ) && ( SyncWordDetected == false ) ) // SyncAddr
{
SyncWordDetected = true;
RxPacketRssiValue = SX1276FskReadRssi( );
RxPacketAfcValue = SX1276FskReadAfc( );
RxGain = SX1276FskReadRxGain( );
Preamble2SyncTimer = RxTimeoutTimer = GET_TICK_COUNT( );
RFState = RF_STATE_RX_RUNNING;
}
// Preamble 2 SyncAddr timeout
if( ( SyncWordDetected == false ) && ( PreambleDetected == true ) && ( ( GET_TICK_COUNT( ) - Preamble2SyncTimer ) > Preamble2SyncTimeout ) )
{
RFState = RF_STATE_RX_INIT;
SX1276Write( REG_RXCONFIG, SX1276->RegRxConfig | RF_RXCONFIG_RESTARTRXWITHPLLLOCK );
}
if( ( SyncWordDetected == false ) &&
( PreambleDetected == false ) &&
( PacketDetected == false ) &&
( ( GET_TICK_COUNT( ) - RxTimeoutTimer ) > PacketTimeout ) )
{
RFState = RF_STATE_RX_TIMEOUT;
}
break;
case RF_STATE_RX_RUNNING:
if( RxPacketSize > RF_BUFFER_SIZE_MAX )
{
RFState = RF_STATE_RX_LEN_ERROR;
break;
}
#if 1
if( DIO1 == 1 ) // FifoLevel
{
if( ( RxPacketSize == 0 ) && ( RxBytesRead == 0 ) ) // Read received packet size
{
if( ( SX1276->RegPacketConfig1 & RF_PACKETCONFIG1_PACKETFORMAT_VARIABLE ) == RF_PACKETCONFIG1_PACKETFORMAT_VARIABLE )
{
SX1276ReadFifo( ( uint8_t* )&RxPacketSize, 1 );
}
else
{
RxPacketSize = SX1276->RegPayloadLength;
}
}
if( ( RxPacketSize - RxBytesRead ) > ( SX1276->RegFifoThresh & 0x3F ) )
{
SX1276ReadFifo( ( RFBuffer + RxBytesRead ), ( SX1276->RegFifoThresh & 0x3F ) );
RxBytesRead += ( SX1276->RegFifoThresh & 0x3F );
}
else
{
SX1276ReadFifo( ( RFBuffer + RxBytesRead ), RxPacketSize - RxBytesRead );
RxBytesRead += ( RxPacketSize - RxBytesRead );
}
}
#endif
if( DIO0 == 1 ) // PayloadReady/CrcOk
{
RxTimeoutTimer = GET_TICK_COUNT( );
if( ( RxPacketSize == 0 ) && ( RxBytesRead == 0 ) ) // Read received packet size
{
if( ( SX1276->RegPacketConfig1 & RF_PACKETCONFIG1_PACKETFORMAT_VARIABLE ) == RF_PACKETCONFIG1_PACKETFORMAT_VARIABLE )
{
SX1276ReadFifo( ( uint8_t* )&RxPacketSize, 1 );
}
else
{
RxPacketSize = SX1276->RegPayloadLength;
}
SX1276ReadFifo( RFBuffer + RxBytesRead, RxPacketSize - RxBytesRead );
RxBytesRead += ( RxPacketSize - RxBytesRead );
PacketDetected = true;
RFState = RF_STATE_RX_DONE;
}
else
{
SX1276ReadFifo( RFBuffer + RxBytesRead, RxPacketSize - RxBytesRead );
RxBytesRead += ( RxPacketSize - RxBytesRead );
PacketDetected = true;
RFState = RF_STATE_RX_DONE;
}
}
// Packet timeout
if( ( PacketDetected == false ) && ( ( GET_TICK_COUNT( ) - RxTimeoutTimer ) > PacketTimeout ) )
{
RFState = RF_STATE_RX_TIMEOUT;
}
break;
case RF_STATE_RX_DONE:
RxBytesRead = 0;
RFState = RF_STATE_RX_INIT;
result = RF_RX_DONE;
break;
case RF_STATE_RX_TIMEOUT:
RxBytesRead = 0;
RxPacketSize = 0;
SX1276Write( REG_RXCONFIG, SX1276->RegRxConfig | RF_RXCONFIG_RESTARTRXWITHPLLLOCK );
RFState = RF_STATE_RX_INIT;
result = RF_RX_TIMEOUT;
break;
case RF_STATE_RX_LEN_ERROR:
RxBytesRead = 0;
RxPacketSize = 0;
SX1276Write( REG_RXCONFIG, SX1276->RegRxConfig | RF_RXCONFIG_RESTARTRXWITHPLLLOCK );
RFState = RF_STATE_RX_INIT;
result = RF_LEN_ERROR;
break;
// Tx management
case RF_STATE_TX_INIT:
// Packet DIO mapping setup
// PacketSent, FifoLevel, FifoFull, TxReady
SX1276->RegDioMapping1 = RF_DIOMAPPING1_DIO0_00 | RF_DIOMAPPING1_DIO1_00 | RF_DIOMAPPING1_DIO2_00 | RF_DIOMAPPING1_DIO3_01;
// LowBat, Data
SX1276->RegDioMapping2 = RF_DIOMAPPING2_DIO4_00 | RF_DIOMAPPING2_DIO5_10;
SX1276WriteBuffer( REG_DIOMAPPING1, &SX1276->RegDioMapping1, 2 );
SX1276->RegFifoThresh = RF_FIFOTHRESH_TXSTARTCONDITION_FIFONOTEMPTY | 0x18; // 24 bytes of data
SX1276Write( REG_FIFOTHRESH, SX1276->RegFifoThresh );
SX1276FskSetOpMode( RF_OPMODE_TRANSMITTER );
RFState = RF_STATE_TX_READY_WAIT;
TxBytesSent = 0;
break;
case RF_STATE_TX_READY_WAIT:
if( DIO3 == 1 ) // TxReady
{
if( ( SX1276->RegPacketConfig1 & RF_PACKETCONFIG1_PACKETFORMAT_VARIABLE ) == RF_PACKETCONFIG1_PACKETFORMAT_VARIABLE )
{
SX1276WriteFifo( ( uint8_t* )&TxPacketSize, 1 );
}
if( ( TxPacketSize > 0 ) && ( TxPacketSize <= 64 ) )
{
DataChunkSize = TxPacketSize;
}
else
{
DataChunkSize = 32;
}
SX1276WriteFifo( RFBuffer, DataChunkSize );
TxBytesSent += DataChunkSize;
TxTimeoutTimer = GET_TICK_COUNT( );
RFState = RF_STATE_TX_RUNNING;
}
break;
case RF_STATE_TX_RUNNING:
if( DIO1 == 0 ) // FifoLevel below thresold
{
if( ( TxPacketSize - TxBytesSent ) > DataChunkSize )
{
SX1276WriteFifo( ( RFBuffer + TxBytesSent ), DataChunkSize );
TxBytesSent += DataChunkSize;
}
else
{
// we write the last chunk of data
SX1276WriteFifo( RFBuffer + TxBytesSent, TxPacketSize - TxBytesSent );
TxBytesSent += TxPacketSize - TxBytesSent;
}
}
if( DIO0 == 1 ) // PacketSent
{
TxTimeoutTimer = GET_TICK_COUNT( );
RFState = RF_STATE_TX_DONE;
SX1276FskSetOpMode( RF_OPMODE_STANDBY );
}
// Packet timeout
if( ( GET_TICK_COUNT( ) - TxTimeoutTimer ) > TICK_RATE_MS( 1000 ) )
{
RFState = RF_STATE_TX_TIMEOUT;
}
break;
case RF_STATE_TX_DONE:
RFState = RF_STATE_IDLE;
result = RF_TX_DONE;
break;
case RF_STATE_TX_TIMEOUT:
RFState = RF_STATE_IDLE;
result = RF_TX_TIMEOUT;
break;
default:
break;
}
return result;
}
#endif // USE_SX1276_RADIO
@@ -0,0 +1,532 @@
/*
* THE FOLLOWING FIRMWARE IS PROVIDED: (1) "AS IS" WITH NO WARRANTY; AND
* (2)TO ENABLE ACCESS TO CODING INFORMATION TO GUIDE AND FACILITATE CUSTOMER.
* CONSEQUENTLY, SEMTECH SHALL NOT BE HELD LIABLE FOR ANY DIRECT, INDIRECT OR
* CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE CONTENT
* OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING INFORMATION
* CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*
* Copyright (C) SEMTECH S.A.
*/
/*!
* \file sx1276-FskMisc.c
* \brief SX1276 RF chip high level functions driver
*
* \remark Optional support functions.
* These functions are defined only to easy the change of the
* parameters.
* For a final firmware the radio parameters will be known so
* there is no need to support all possible parameters.
* Removing these functions will greatly reduce the final firmware
* size.
*
* \version 2.0.0
* \date May 6 2013
* \author Gregory Cristian
*
* Last modified by Miguel Luis on Jun 19 2013
*/
/*************************************************
File name: sx1276-FskMisc.c
Description: support aiit board configure and register function
History:
1. Date: 2021-04-25
Author: AIIT XUOS Lab
Modification:
1. replace original macro and basic date type with AIIT XUOS Lab's own defination
*************************************************/
#include <math.h>
#include "platform.h"
#if defined( USE_SX1276_RADIO )
#include "sx1276-Hal.h"
#include "sx1276.h"
#include "sx1276-Fsk.h"
#include "sx1276-FskMisc.h"
extern tFskSettings FskSettings;
void SX1276FskSetRFFrequency( uint32_t freq )
{
FskSettings.RFFrequency = freq;
freq = ( uint32_t )( ( double )freq / ( double )FREQ_STEP );
SX1276->RegFrfMsb = ( uint8_t )( ( freq >> 16 ) & 0xFF );
SX1276->RegFrfMid = ( uint8_t )( ( freq >> 8 ) & 0xFF );
SX1276->RegFrfLsb = ( uint8_t )( freq & 0xFF );
SX1276WriteBuffer( REG_FRFMSB, &SX1276->RegFrfMsb, 3 );
}
uint32_t SX1276FskGetRFFrequency( void )
{
SX1276ReadBuffer( REG_FRFMSB, &SX1276->RegFrfMsb, 3 );
FskSettings.RFFrequency = ( ( uint32_t )SX1276->RegFrfMsb << 16 ) | ( ( uint32_t )SX1276->RegFrfMid << 8 ) | ( ( uint32_t )SX1276->RegFrfLsb );
FskSettings.RFFrequency = ( uint32_t )( ( double )FskSettings.RFFrequency * ( double )FREQ_STEP );
return FskSettings.RFFrequency;
}
void SX1276FskRxCalibrate( void )
{
// the function RadioRxCalibrate is called just after the reset so all register are at their default values
uint8_t regPaConfigInitVal;
uint32_t initialFreq;
// save register values;
SX1276Read( REG_PACONFIG, &regPaConfigInitVal );
initialFreq = SX1276FskGetRFFrequency( );
// Cut the PA just in case
SX1276->RegPaConfig = 0x00; // RFO output, power = -1 dBm
SX1276Write( REG_PACONFIG, SX1276->RegPaConfig );
// Set Frequency in HF band
SX1276FskSetRFFrequency( 860000000 );
// Rx chain re-calibration workaround
SX1276Read( REG_IMAGECAL, &SX1276->RegImageCal );
SX1276->RegImageCal = ( SX1276->RegImageCal & RF_IMAGECAL_IMAGECAL_MASK ) | RF_IMAGECAL_IMAGECAL_START;
SX1276Write( REG_IMAGECAL, SX1276->RegImageCal );
SX1276Read( REG_IMAGECAL, &SX1276->RegImageCal );
// rx_cal_run goes low when calibration in finished
while( ( SX1276->RegImageCal & RF_IMAGECAL_IMAGECAL_RUNNING ) == RF_IMAGECAL_IMAGECAL_RUNNING )
{
SX1276Read( REG_IMAGECAL, &SX1276->RegImageCal );
}
// reload saved values into the registers
SX1276->RegPaConfig = regPaConfigInitVal;
SX1276Write( REG_PACONFIG, SX1276->RegPaConfig );
SX1276FskSetRFFrequency( initialFreq );
}
void SX1276FskSetBitrate( uint32_t bitrate )
{
FskSettings.Bitrate = bitrate;
bitrate = ( uint16_t )( ( double )XTAL_FREQ / ( double )bitrate );
SX1276->RegBitrateMsb = ( uint8_t )( bitrate >> 8 );
SX1276->RegBitrateLsb = ( uint8_t )( bitrate & 0xFF );
SX1276WriteBuffer( REG_BITRATEMSB, &SX1276->RegBitrateMsb, 2 );
}
uint32_t SX1276FskGetBitrate( void )
{
SX1276ReadBuffer( REG_BITRATEMSB, &SX1276->RegBitrateMsb, 2 );
FskSettings.Bitrate = ( ( ( uint32_t )SX1276->RegBitrateMsb << 8 ) | ( ( uint32_t )SX1276->RegBitrateLsb ) );
FskSettings.Bitrate = ( uint16_t )( ( double )XTAL_FREQ / ( double )FskSettings.Bitrate );
return FskSettings.Bitrate;
}
void SX1276FskSetFdev( uint32_t fdev )
{
FskSettings.Fdev = fdev;
SX1276Read( REG_FDEVMSB, &SX1276->RegFdevMsb );
fdev = ( uint16_t )( ( double )fdev / ( double )FREQ_STEP );
SX1276->RegFdevMsb = ( ( SX1276->RegFdevMsb & RF_FDEVMSB_FDEV_MASK ) | ( ( ( uint8_t )( fdev >> 8 ) ) & ~RF_FDEVMSB_FDEV_MASK ) );
SX1276->RegFdevLsb = ( uint8_t )( fdev & 0xFF );
SX1276WriteBuffer( REG_FDEVMSB, &SX1276->RegFdevMsb, 2 );
}
uint32_t SX1276FskGetFdev( void )
{
SX1276ReadBuffer( REG_FDEVMSB, &SX1276->RegFdevMsb, 2 );
FskSettings.Fdev = ( ( ( uint32_t )( ( SX1276->RegFdevMsb << 8 ) & ~RF_FDEVMSB_FDEV_MASK ) ) | ( ( uint32_t )SX1276->RegFdevLsb ) );
FskSettings.Fdev = ( uint16_t )( ( double )FskSettings.Fdev * ( double )FREQ_STEP );
return FskSettings.Fdev;
}
void SX1276FskSetRFPower( int8_t power )
{
SX1276Read( REG_PACONFIG, &SX1276->RegPaConfig );
SX1276Read( REG_PADAC, &SX1276->RegPaDac );
if( ( SX1276->RegPaConfig & RF_PACONFIG_PASELECT_PABOOST ) == RF_PACONFIG_PASELECT_PABOOST )
{
if( ( SX1276->RegPaDac & 0x87 ) == 0x87 )
{
if( power < 5 )
{
power = 5;
}
if( power > 20 )
{
power = 20;
}
SX1276->RegPaConfig = ( SX1276->RegPaConfig & RF_PACONFIG_MAX_POWER_MASK ) | 0x70;
SX1276->RegPaConfig = ( SX1276->RegPaConfig & RF_PACONFIG_OUTPUTPOWER_MASK ) | ( uint8_t )( ( uint16_t )( power - 5 ) & 0x0F );
}
else
{
if( power < 2 )
{
power = 2;
}
if( power > 17 )
{
power = 17;
}
SX1276->RegPaConfig = ( SX1276->RegPaConfig & RF_PACONFIG_MAX_POWER_MASK ) | 0x70;
SX1276->RegPaConfig = ( SX1276->RegPaConfig & RF_PACONFIG_OUTPUTPOWER_MASK ) | ( uint8_t )( ( uint16_t )( power - 2 ) & 0x0F );
}
}
else
{
if( power < -1 )
{
power = -1;
}
if( power > 14 )
{
power = 14;
}
SX1276->RegPaConfig = ( SX1276->RegPaConfig & RF_PACONFIG_MAX_POWER_MASK ) | 0x70;
SX1276->RegPaConfig = ( SX1276->RegPaConfig & RF_PACONFIG_OUTPUTPOWER_MASK ) | ( uint8_t )( ( uint16_t )( power + 1 ) & 0x0F );
}
SX1276Write( REG_PACONFIG, SX1276->RegPaConfig );
FskSettings.Power = power;
}
int8_t SX1276FskGetRFPower( void )
{
SX1276Read( REG_PACONFIG, &SX1276->RegPaConfig );
SX1276Read( REG_PADAC, &SX1276->RegPaDac );
if( ( SX1276->RegPaConfig & RF_PACONFIG_PASELECT_PABOOST ) == RF_PACONFIG_PASELECT_PABOOST )
{
if( ( SX1276->RegPaDac & 0x07 ) == 0x07 )
{
FskSettings.Power = 5 + ( SX1276->RegPaConfig & ~RF_PACONFIG_OUTPUTPOWER_MASK );
}
else
{
FskSettings.Power = 2 + ( SX1276->RegPaConfig & ~RF_PACONFIG_OUTPUTPOWER_MASK );
}
}
else
{
FskSettings.Power = -1 + ( SX1276->RegPaConfig & ~RF_PACONFIG_OUTPUTPOWER_MASK );
}
return FskSettings.Power;
}
/*!
* \brief Computes the Rx bandwidth with the mantisse and exponent
*
* \param [IN] mantisse Mantisse of the bandwidth value
* \param [IN] exponent Exponent of the bandwidth value
* \retval bandwidth Computed bandwidth
*/
static uint32_t SX1276FskComputeRxBw( uint8_t mantisse, uint8_t exponent )
{
// rxBw
if( ( SX1276->RegOpMode & RF_OPMODE_MODULATIONTYPE_FSK ) == RF_OPMODE_MODULATIONTYPE_FSK )
{
return ( uint32_t )( ( double )XTAL_FREQ / ( mantisse * ( double )pow( 2, exponent + 2 ) ) );
}
else
{
return ( uint32_t )( ( double )XTAL_FREQ / ( mantisse * ( double )pow( 2, exponent + 3 ) ) );
}
}
/*!
* \brief Computes the mantisse and exponent from the bandwitdh value
*
* \param [IN] rxBwValue Bandwidth value
* \param [OUT] mantisse Mantisse of the bandwidth value
* \param [OUT] exponent Exponent of the bandwidth value
*/
static void SX1276FskComputeRxBwMantExp( uint32_t rxBwValue, uint8_t* mantisse, uint8_t* exponent )
{
uint8_t tmpExp = 0;
uint8_t tmpMant = 0;
double tmpRxBw = 0;
double rxBwMin = 10e6;
for( tmpExp = 0; tmpExp < 8; tmpExp++ )
{
for( tmpMant = 16; tmpMant <= 24; tmpMant += 4 )
{
if( ( SX1276->RegOpMode & RF_OPMODE_MODULATIONTYPE_FSK ) == RF_OPMODE_MODULATIONTYPE_FSK )
{
tmpRxBw = ( double )XTAL_FREQ / ( tmpMant * ( double )pow( 2, tmpExp + 2 ) );
}
else
{
tmpRxBw = ( double )XTAL_FREQ / ( tmpMant * ( double )pow( 2, tmpExp + 3 ) );
}
if( fabs( tmpRxBw - rxBwValue ) < rxBwMin )
{
rxBwMin = fabs( tmpRxBw - rxBwValue );
*mantisse = tmpMant;
*exponent = tmpExp;
}
}
}
}
void SX1276FskSetDccBw( uint8_t* reg, uint32_t dccValue, uint32_t rxBwValue )
{
uint8_t mantisse = 0;
uint8_t exponent = 0;
if( reg == &SX1276->RegRxBw )
{
*reg = ( uint8_t )dccValue & 0x60;
}
else
{
*reg = 0;
}
SX1276FskComputeRxBwMantExp( rxBwValue, &mantisse, &exponent );
switch( mantisse )
{
case 16:
*reg |= ( uint8_t )( 0x00 | ( exponent & 0x07 ) );
break;
case 20:
*reg |= ( uint8_t )( 0x08 | ( exponent & 0x07 ) );
break;
case 24:
*reg |= ( uint8_t )( 0x10 | ( exponent & 0x07 ) );
break;
default:
// Something went terribely wrong
break;
}
if( reg == &SX1276->RegRxBw )
{
SX1276Write( REG_RXBW, *reg );
FskSettings.RxBw = rxBwValue;
}
else
{
SX1276Write( REG_AFCBW, *reg );
FskSettings.RxBwAfc = rxBwValue;
}
}
uint32_t SX1276FskGetBw( uint8_t* reg )
{
uint32_t rxBwValue = 0;
uint8_t mantisse = 0;
switch( ( *reg & 0x18 ) >> 3 )
{
case 0:
mantisse = 16;
break;
case 1:
mantisse = 20;
break;
case 2:
mantisse = 24;
break;
default:
break;
}
rxBwValue = SX1276FskComputeRxBw( mantisse, ( uint8_t )*reg & 0x07 );
if( reg == &SX1276->RegRxBw )
{
return FskSettings.RxBw = rxBwValue;
}
else
{
return FskSettings.RxBwAfc = rxBwValue;
}
}
void SX1276FskSetPacketCrcOn( bool enable )
{
SX1276Read( REG_PACKETCONFIG1, &SX1276->RegPacketConfig1 );
SX1276->RegPacketConfig1 = ( SX1276->RegPacketConfig1 & RF_PACKETCONFIG1_CRC_MASK ) | ( enable << 4 );
SX1276Write( REG_PACKETCONFIG1, SX1276->RegPacketConfig1 );
FskSettings.CrcOn = enable;
}
bool SX1276FskGetPacketCrcOn( void )
{
SX1276Read( REG_PACKETCONFIG1, &SX1276->RegPacketConfig1 );
FskSettings.CrcOn = ( SX1276->RegPacketConfig1 & RF_PACKETCONFIG1_CRC_ON ) >> 4;
return FskSettings.CrcOn;
}
void SX1276FskSetAfcOn( bool enable )
{
SX1276Read( REG_RXCONFIG, &SX1276->RegRxConfig );
SX1276->RegRxConfig = ( SX1276->RegRxConfig & RF_RXCONFIG_AFCAUTO_MASK ) | ( enable << 4 );
SX1276Write( REG_RXCONFIG, SX1276->RegRxConfig );
FskSettings.AfcOn = enable;
}
bool SX1276FskGetAfcOn( void )
{
SX1276Read( REG_RXCONFIG, &SX1276->RegRxConfig );
FskSettings.AfcOn = ( SX1276->RegRxConfig & RF_RXCONFIG_AFCAUTO_ON ) >> 4;
return FskSettings.AfcOn;
}
void SX1276FskSetPayloadLength( uint8_t value )
{
SX1276->RegPayloadLength = value;
SX1276Write( REG_PAYLOADLENGTH, SX1276->RegPayloadLength );
FskSettings.PayloadLength = value;
}
uint8_t SX1276FskGetPayloadLength( void )
{
SX1276Read( REG_PAYLOADLENGTH, &SX1276->RegPayloadLength );
FskSettings.PayloadLength = SX1276->RegPayloadLength;
return FskSettings.PayloadLength;
}
void SX1276FskSetPa20dBm( bool enale )
{
SX1276Read( REG_PADAC, &SX1276->RegPaDac );
SX1276Read( REG_PACONFIG, &SX1276->RegPaConfig );
if( ( SX1276->RegPaConfig & RF_PACONFIG_PASELECT_PABOOST ) == RF_PACONFIG_PASELECT_PABOOST )
{
if( enale == true )
{
SX1276->RegPaDac = 0x87;
}
}
else
{
SX1276->RegPaDac = 0x84;
}
SX1276Write( REG_PADAC, SX1276->RegPaDac );
}
bool SX1276FskGetPa20dBm( void )
{
SX1276Read( REG_PADAC, &SX1276->RegPaDac );
return ( ( SX1276->RegPaDac & 0x07 ) == 0x07 ) ? true : false;
}
void SX1276FskSetPAOutput( uint8_t outputPin )
{
SX1276Read( REG_PACONFIG, &SX1276->RegPaConfig );
SX1276->RegPaConfig = (SX1276->RegPaConfig & RF_PACONFIG_PASELECT_MASK ) | outputPin;
SX1276Write( REG_PACONFIG, SX1276->RegPaConfig );
}
uint8_t SX1276FskGetPAOutput( void )
{
SX1276Read( REG_PACONFIG, &SX1276->RegPaConfig );
return SX1276->RegPaConfig & ~RF_PACONFIG_PASELECT_MASK;
}
void SX1276FskSetPaRamp( uint8_t value )
{
SX1276Read( REG_PARAMP, &SX1276->RegPaRamp );
SX1276->RegPaRamp = ( SX1276->RegPaRamp & RF_PARAMP_MASK ) | ( value & ~RF_PARAMP_MASK );
SX1276Write( REG_PARAMP, SX1276->RegPaRamp );
}
uint8_t SX1276FskGetPaRamp( void )
{
SX1276Read( REG_PARAMP, &SX1276->RegPaRamp );
return SX1276->RegPaRamp & ~RF_PARAMP_MASK;
}
void SX1276FskSetRssiOffset( int8_t offset )
{
SX1276Read( REG_RSSICONFIG, &SX1276->RegRssiConfig );
if( offset < 0 )
{
offset = ( ~offset & 0x1F );
offset += 1;
offset = -offset;
}
SX1276->RegRssiConfig |= ( uint8_t )( ( offset & 0x1F ) << 3 );
SX1276Write( REG_RSSICONFIG, SX1276->RegRssiConfig );
}
int8_t SX1276FskGetRssiOffset( void )
{
int8_t offset;
SX1276Read( REG_RSSICONFIG, &SX1276->RegRssiConfig );
offset = SX1276->RegRssiConfig >> 3;
if( ( offset & 0x10 ) == 0x10 )
{
offset = ( ~offset & 0x1F );
offset += 1;
offset = -offset;
}
return offset;
}
int8_t SX1276FskGetRawTemp( void )
{
int8_t temp = 0;
uint8_t previousOpMode;
uint32_t startTick;
// Enable Temperature reading
SX1276Read( REG_IMAGECAL, &SX1276->RegImageCal );
SX1276->RegImageCal = ( SX1276->RegImageCal & RF_IMAGECAL_TEMPMONITOR_MASK ) | RF_IMAGECAL_TEMPMONITOR_ON;
SX1276Write( REG_IMAGECAL, SX1276->RegImageCal );
// save current Op Mode
SX1276Read( REG_OPMODE, &SX1276->RegOpMode );
previousOpMode = SX1276->RegOpMode;
// put device in FSK RxSynth
SX1276->RegOpMode = RF_OPMODE_SYNTHESIZER_RX;
SX1276Write( REG_OPMODE, SX1276->RegOpMode );
// Wait 1ms
startTick = GET_TICK_COUNT( );
while( ( GET_TICK_COUNT( ) - startTick ) < TICK_RATE_MS( 1 ) );
// Disable Temperature reading
SX1276Read( REG_IMAGECAL, &SX1276->RegImageCal );
SX1276->RegImageCal = ( SX1276->RegImageCal & RF_IMAGECAL_TEMPMONITOR_MASK ) | RF_IMAGECAL_TEMPMONITOR_OFF;
SX1276Write( REG_IMAGECAL, SX1276->RegImageCal );
// Read temperature
SX1276Read( REG_TEMP, &SX1276->RegTemp );
temp = SX1276->RegTemp & 0x7F;
if( ( SX1276->RegTemp & 0x80 ) == 0x80 )
{
temp *= -1;
}
// Reload previous Op Mode
SX1276Write( REG_OPMODE, previousOpMode );
return temp;
}
int8_t SX1276FskCalibreateTemp( int8_t actualTemp )
{
return actualTemp - SX1276FskGetRawTemp( );
}
int8_t SX1276FskGetTemp( int8_t compensationFactor )
{
return SX1276FskGetRawTemp( ) + compensationFactor;
}
#endif // USE_SX1276_RADIO
@@ -0,0 +1,251 @@
/*
* THE FOLLOWING FIRMWARE IS PROVIDED: (1) "AS IS" WITH NO WARRANTY; AND
* (2)TO ENABLE ACCESS TO CODING INFORMATION TO GUIDE AND FACILITATE CUSTOMER.
* CONSEQUENTLY, SEMTECH SHALL NOT BE HELD LIABLE FOR ANY DIRECT, INDIRECT OR
* CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE CONTENT
* OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING INFORMATION
* CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*
* Copyright (C) SEMTECH S.A.
*/
/*!
* \file sx1276-FskMisc.h
* \brief SX1276 RF chip high level functions driver
*
* \remark Optional support functions.
* These functions are defined only to easy the change of the
* parameters.
* For a final firmware the radio parameters will be known so
* there is no need to support all possible parameters.
* Removing these functions will greatly reduce the final firmware
* size.
*
* \version 2.0.B2
* \date May 6 2013
* \author Gregory Cristian
*
* Last modified by Miguel Luis on Jun 19 2013
*/
/*************************************************
File name: sx1276-FskMisc.h
Description: support aiit board configure and register function
History:
1. Date: 2021-04-25
Author: AIIT XUOS Lab
Modification:
1. replace original macro and basic date type with AIIT XUOS Lab's own defination
*************************************************/
#ifndef __SX1276_FSK_MISC_H__
#define __SX1276_FSK_MISC_H__
/*!
* \brief Writes the new RF frequency value
*
* \param [IN] freq New RF frequency value in [Hz]
*/
void SX1276FskSetRFFrequency( uint32_t freq );
/*!
* \brief Reads the current RF frequency value
*
* \retval freq Current RF frequency value in [Hz]
*/
uint32_t SX1276FskGetRFFrequency( void );
/*!
* \brief Calibrate RSSI and I/Q mismatch for HF
*
* \retval none
*/
void SX1276FskRxCalibrate( void );
/*!
* \brief Writes the new bitrate value
*
* \param [IN] bitrate New bitrate value in [bps]
*/
void SX1276FskSetBitrate( uint32_t bitrate );
/*!
* \brief Reads the current bitrate value
*
* \retval bitrate Current bitrate value in [bps]
*/
uint32_t SX1276FskGetBitrate( void );
/*!
* \brief Writes the new frequency deviation value
*
* \param [IN] fdev New frequency deviation value in [Hz]
*/
void SX1276FskSetFdev( uint32_t fdev );
/*!
* \brief Reads the current frequency deviation value
*
* \retval fdev Current frequency deviation value in [Hz]
*/
uint32_t SX1276FskGetFdev( void );
/*!
* \brief Writes the new RF output power value
*
* \param [IN] power New output power value in [dBm]
*/
void SX1276FskSetRFPower( int8_t power );
/*!
* \brief Reads the current RF output power value
*
* \retval power Current output power value in [dBm]
*/
int8_t SX1276FskGetRFPower( void );
/*!
* \brief Writes the DC offset canceller and Rx bandwidth values
*
* \remark For SX1276 there is no DCC setting. dccValue should be 0
* ie: SX1276SetDccBw( &SX1276.RegRxBw, 0, 62500 );
*
* \param [IN] reg Register pointer to either SX1231.RegRxBw or SX1231.RegAfcBw
* \param [IN] dccValue New DC offset canceller value in [Hz] ( SX1231 only )
* \param [IN] rxBwValue New Rx bandwidth value in [Hz]
*/
void SX1276FskSetDccBw( uint8_t* reg, uint32_t dccValue, uint32_t rxBwValue );
/*!
* \brief Reads the current bandwidth setting
*
* \param [IN] reg Register pointer to either SX1231.RegRxBw or SX1231.RegAfcBw
*
* \retval bandwidth Bandwidth value
*/
uint32_t SX1276FskGetBw( uint8_t* reg );
/*!
* \brief Enables/Disables CRC
*
* \param [IN] enable CRC enable/disable
*/
void SX1276FskSetPacketCrcOn( bool enable );
/*!
* \brief Reads the current CRC Enable/Disbale value
*
* \retval enable Current CRC Enable/Disbale value
*/
bool SX1276FskGetPacketCrcOn( void );
/*!
* \brief Enables/Disables AFC
*
* \param [IN] enable AFC enable/disable
*/
void SX1276FskSetAfcOn( bool enable );
/*!
* \brief Reads the current AFC Enable/Disbale value
*
* \retval enable Current AFC Enable/Disbale value
*/
bool SX1276FskGetAfcOn( void );
/*!
* \brief Writes the new payload length value
*
* \param [IN] value New payload length value
*/
void SX1276FskSetPayloadLength( uint8_t value );
/*!
* \brief Reads the current payload length value
*
* \retval value Current payload length value
*/
uint8_t SX1276FskGetPayloadLength( void );
/*!
* \brief Enables/Disables the 20 dBm PA
*
* \param [IN] enable [true, false]
*/
void SX1276FskSetPa20dBm( bool enale );
/*!
* \brief Gets the current 20 dBm PA status
*
* \retval enable [true, false]
*/
bool SX1276FskGetPa20dBm( void );
/*!
* \brief Set the RF Output pin
*
* \param [IN] RF_PACONFIG_PASELECT_PABOOST or RF_PACONFIG_PASELECT_RFO
*/
void SX1276FskSetPAOutput( uint8_t outputPin );
/*!
* \brief Gets the used RF Ouptu pin
*
* \retval RF_PACONFIG_PASELECT_PABOOST or RF_PACONFIG_PASELECT_RFO
*/
uint8_t SX1276FskGetPAOutput( void );
/*!
* \brief Writes the new PA rise/fall time of ramp up/down value
*
* \param [IN] value New PaRamp value
*/
void SX1276FskSetPaRamp( uint8_t value );
/*!
* \brief Reads the current PA rise/fall time of ramp up/down value
*
* \retval value Current PaRamp value
*/
uint8_t SX1276FskGetPaRamp( void );
/*!
* \brief Applies an offset to the RSSI. Compensates board components
*
* \param [IN] offset Offset to be applied (+/-)
*/
void SX1276FskSetRssiOffset( int8_t offset );
/*!
* \brief Gets the current RSSI offset.
*
* \retval offset Current offset (+/-)
*/
int8_t SX1276FskGetRssiOffset( void );
/*!
* \brief Writes the new value for the preamble size
*
* \param [IN] size New value of pramble size
*/
void SX1276FskSetPreambleSize( uint16_t size );
/*!
* Reads the raw temperature
* \retval temperature New raw temperature reading in 2's complement format
*/
int8_t SX1276FskGetRawTemp( void );
/*!
* Computes the temperature compensation factor
* \param [IN] actualTemp Actual temperature measured by an external device
* \retval compensationFactor Computed compensation factor
*/
int8_t SX1276FskCalibreateTemp( int8_t actualTemp );
/*!
* Gets the actual compensated temperature
* \param [IN] compensationFactor Return value of the calibration function
* \retval New compensated temperature value
*/
int8_t SX1276FskGetTemp( int8_t compensationFactor );
#endif //__SX1276_FSK_MISC_H__
@@ -0,0 +1,170 @@
/*
* THE FOLLOWING FIRMWARE IS PROVIDED: (1) "AS IS" WITH NO WARRANTY; AND
* (2)TO ENABLE ACCESS TO CODING INFORMATION TO GUIDE AND FACILITATE CUSTOMER.
* CONSEQUENTLY, SEMTECH SHALL NOT BE HELD LIABLE FOR ANY DIRECT, INDIRECT OR
* CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE CONTENT
* OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING INFORMATION
* CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*
* Copyright (C) SEMTECH S.A.
*/
/*!
* \file sx1276-Hal.h
* \brief SX1276 Hardware Abstraction Layer
*
* \version 2.0.B2
* \date Nov 21 2012
* \author Miguel Luis
*
* Last modified by Miguel Luis on Jun 19 2013
*/
/*************************************************
File name: sx1276-Hal.h
Description: support aiit board configure and register function
History:
1. Date: 2021-04-25
Author: AIIT XUOS Lab
Modification:
1. replace original macro and basic date type with AIIT XUOS Lab's own defination
*************************************************/
#ifndef __SX1276_HAL_H__
#define __SX1276_HAL_H__
#include "platform.h"
/*!
* DIO state read functions mapping
*/
#define DIO0 SX1276ReadDio0( )
#define DIO1 SX1276ReadDio1( )
#define DIO2 SX1276ReadDio2( )
#define DIO3 SX1276ReadDio3( )
#define DIO4 SX1276ReadDio4( )
#define DIO5 SX1276ReadDio5( )
// RXTX pin control see errata note
#define RXTX( txEnable ) SX1276WriteRxTx( txEnable );
#define GET_TICK_COUNT( ) CurrentTicksGain()
#define TICK_RATE_MS( ms ) ( ms )
typedef enum
{
RADIO_RESET_OFF,
RADIO_RESET_ON,
}tRadioResetState;
/*!
* \brief Initializes the radio interface I/Os
*/
void SX1276InitIo( void );
/*!
* \brief Set the radio reset pin state
*
* \param state New reset pin state
*/
void SX1276SetReset( uint8_t state );
/*!
* \brief Writes the radio register at the specified address
*
* \param [IN]: addr Register address
* \param [IN]: data New register value
*/
void SX1276Write( uint8_t addr, uint8_t data );
/*!
* \brief Reads the radio register at the specified address
*
* \param [IN]: addr Register address
* \param [OUT]: data Register value
*/
void SX1276Read( uint8_t addr, uint8_t *data );
/*!
* \brief Writes multiple radio registers starting at address
*
* \param [IN] addr First Radio register address
* \param [IN] buffer Buffer containing the new register's values
* \param [IN] size Number of registers to be written
*/
void SX1276WriteBuffer( uint8_t addr, uint8_t *buffer, uint8_t size );
/*!
* \brief Reads multiple radio registers starting at address
*
* \param [IN] addr First Radio register address
* \param [OUT] buffer Buffer where to copy the registers data
* \param [IN] size Number of registers to be read
*/
void SX1276ReadBuffer( uint8_t addr, uint8_t *buffer, uint8_t size );
/*!
* \brief Writes the buffer contents to the radio FIFO
*
* \param [IN] buffer Buffer containing data to be put on the FIFO.
* \param [IN] size Number of bytes to be written to the FIFO
*/
void SX1276WriteFifo( uint8_t *buffer, uint8_t size );
/*!
* \brief Reads the contents of the radio FIFO
*
* \param [OUT] buffer Buffer where to copy the FIFO read data.
* \param [IN] size Number of bytes to be read from the FIFO
*/
void SX1276ReadFifo( uint8_t *buffer, uint8_t size );
/*!
* \brief Gets the SX1276 DIO0 hardware pin status
*
* \retval status Current hardware pin status [1, 0]
*/
inline uint8_t SX1276ReadDio0( void );
/*!
* \brief Ge// USE_SX1276_RADIOts the SX1276 DIO1 hardware pin status
*
* \retval status Current hardware pin status [1, 0]
*/
inline uint8_t SX1276ReadDio1( void );
/*!
* \brief Gets the SX1276 DIO2 hardware pin status
*
* \retval status Current hardware pin status [1, 0]
*/
inline uint8_t SX1276ReadDio2( void );
/*!
* \brief Gets the SX1276 DIO3 hardware pin status
*
* \retval status Current hardware pin status [1, 0]
*/
inline uint8_t SX1276ReadDio3( void );
/*!
* \brief Gets the SX1276 DIO4 hardware pin status
*
* \retval status Current hardware pin status [1, 0]
*/
inline uint8_t SX1276ReadDio4( void );
/*!
* \brief Gets the SX1276 DIO5 hardware pin status
*
* \retval status Current hardware pin status [1, 0]
*/
inline uint8_t SX1276ReadDio5( void );
/*!
* \brief Writes the external RxTx pin value
*
* \remark see errata note
*
* \param [IN] txEnable [1: Tx, 0: Rx]
*/
inline void SX1276WriteRxTx( uint8_t txEnable );
#endif //__SX1276_HAL_H__
@@ -0,0 +1,723 @@
/*
* THE FOLLOWING FIRMWARE IS PROVIDED: (1) "AS IS" WITH NO WARRANTY; AND
* (2)TO ENABLE ACCESS TO CODING INFORMATION TO GUIDE AND FACILITATE CUSTOMER.
* CONSEQUENTLY, SEMTECH SHALL NOT BE HELD LIABLE FOR ANY DIRECT, INDIRECT OR
* CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE CONTENT
* OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING INFORMATION
* CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*
* Original Copyright (C) SEMTECH S.A.
* Modified Copyright (C) 2020 AIIT XUOS Lab
*/
/*!
* \file sx1276-LoRa.c
* \brief SX1276 RF chip driver mode LoRa
*
* \version 2.0.0
* \date Nov 21 2012
* \author Miguel Luis
*
* Last modified by Miguel Luis on Jun 19 2013
*/
/*************************************************
File name: sx1276-LoRa.c
Description: support aiit board configure and register function
History:
1. Date: 2021-04-25
Author: AIIT XUOS Lab
Modification:
1. replace original macro and basic date type with AIIT XUOS Lab's own defination
*************************************************/
#include <string.h>
#include "platform.h"
#if defined( USE_SX1276_RADIO )
#include "radio.h"
#include "sx1276-Hal.h"
#include "sx1276.h"
#include "sx1276-LoRaMisc.h"
#include "sx1276-LoRa.h"
#define LoRa_FREQENCY 433000000
#define RSSI_OFFSET_LF -155.0
#define RSSI_OFFSET_HF -150.0
#define NOISE_ABSOLUTE_ZERO -174.0
#define NOISE_FIGURE_LF 4.0
#define NOISE_FIGURE_HF 6.0
volatile uint32 TickCounter = 0;
uint32 Tx_Time_Start,Tx_Time_End;
uint32 Rx_Time_Start,Rx_Time_End;
//Signal bandwidth, used to calculate RSSI
const double SignalBwLog[] =
{
3.8927900303521316335038277369285, // 7.8 kHz
4.0177301567005500940384239336392, // 10.4 kHz
4.193820026016112828717566631653, // 15.6 kHz
4.31875866931372901183597627752391, // 20.8 kHz
4.4948500216800940239313055263775, // 31.2 kHz
4.6197891057238405255051280399961, // 41.6 kHz
4.795880017344075219145044421102, // 62.5 kHz
5.0969100130080564143587833158265, // 125 kHz
5.397940008672037609572522210551, // 250 kHz
5.6989700043360188047862611052755 // 500 kHz
};
//These values need testing
const double RssiOffsetLF[] =
{
-155.0,
-155.0,
-155.0,
-155.0,
-155.0,
-155.0,
-155.0,
-155.0,
-155.0,
-155.0,
};
//These values need testing
const double RssiOffsetHF[] =
{
-150.0,
-150.0,
-150.0,
-150.0,
-150.0,
-150.0,
-150.0,
-150.0,
-150.0,
-150.0,
};
/*!
* Frequency hopping frequencies table
*/
const int32_t HoppingFrequencies[] =
{
916500000,
923500000,
906500000,
917500000,
917500000,
909000000,
903000000,
916000000,
912500000,
926000000,
925000000,
909500000,
913000000,
918500000,
918500000,
902500000,
911500000,
926500000,
902500000,
922000000,
924000000,
903500000,
913000000,
922000000,
926000000,
910000000,
920000000,
922500000,
911000000,
922000000,
909500000,
926000000,
922000000,
918000000,
925500000,
908000000,
917500000,
926500000,
908500000,
916000000,
905500000,
916000000,
903000000,
905000000,
915000000,
913000000,
907000000,
910000000,
926500000,
925500000,
911000000,
};
// Default settings
tLoRaSettings LoRaSettings =
{
LoRa_FREQENCY , // RFFrequency
20, // Power
9, // SignalBw [0: 125 kHz, 1: 250 kHz, 2: 500 kHz, 3: Reserved]
12, // SpreadingFactor [6: 64, 7: 128, 8: 256, 9: 512, 10: 1024, 11: 2048, 12: 4096 chips]
2, // ErrorCoding [1: 4/5, 2: 4/6, 3: 4/7, 4: 4/8]
true, // CrcOn [0: OFF, 1: ON]
false, // ImplicitHeaderOn [0: OFF, 1: ON]
0, // RxSingleOn [0: Continuous, 1 Single]
0, // FreqHopOn [0: OFF, 1: ON]
4, // HopPeriod Hops every frequency hopping period symbols
1000, // TxPacketTimeout
1000, // RxPacketTimeout
128, // PayloadLength (used for implicit header mode)
};
/*!
* SX1276 LoRa registers variable
*/
tSX1276LR* SX1276LR;
/*!
* Local RF buffer for communication support
*/
static uint8_t RFBuffer[RF_BUFFER_SIZE];
static uint8_t TFBuffer[RF_BUFFER_SIZE];
/*!
* RF state machine variable
*/
static uint8_t RFLRState = RFLR_STATE_IDLE;
/*!
* Rx management support variables
*/
static uint16_t RxPacketSize = 0;
static int8_t RxPacketSnrEstimate;
static double RxPacketRssiValue;
static uint8_t RxGain = 1;
static uint32_t RxTimeoutTimer = 0;
/*!
* PacketTimeout Stores the Rx window time value for packet reception
*/
static uint32_t PacketTimeout;
/*!
* Tx management support variables
*/
static uint16_t TxPacketSize = 0;
void SX1276LoRaInit( void )
{
RFLRState = RFLR_STATE_IDLE;
SX1276LoRaSetDefaults();
SX1276ReadBuffer( REG_LR_OPMODE, SX1276Regs + 1, 0x70 - 1 );
//SX1276LoRaSetOpMode( RFLR_OPMODE_SLEEP );
SX1276LR->RegLna = RFLR_LNA_GAIN_G1;
SX1276WriteBuffer( REG_LR_OPMODE, SX1276Regs + 1, 0x70 - 1 );
// set the RF settings
SX1276LoRaSetRFFrequency( LoRaSettings.RFFrequency );
SX1276LoRaSetSpreadingFactor( LoRaSettings.SpreadingFactor );
SX1276LoRaSetErrorCoding( LoRaSettings.ErrorCoding );
SX1276LoRaSetPacketCrcOn( LoRaSettings.CrcOn );
SX1276LoRaSetSignalBandwidth( LoRaSettings.SignalBw );
SX1276LoRaSetImplicitHeaderOn( LoRaSettings.ImplicitHeaderOn );
SX1276LoRaSetSymbTimeout(0x3FF);
SX1276LoRaSetPayloadLength( LoRaSettings.PayloadLength );
SX1276LoRaSetLowDatarateOptimize( true );
#if( ( MODULE_SX1276RF1IAS == 1 ) || ( MODULE_SX1276RF1KAS == 1 ) )
if( LoRaSettings.RFFrequency > 860000000 )
{
SX1276LoRaSetPAOutput( RFLR_PACONFIG_PASELECT_RFO );
SX1276LoRaSetPa20dBm( false );
LoRaSettings.Power = 14;
SX1276LoRaSetRFPower( LoRaSettings.Power );
}
else
{
//SX1276Write( REG_LR_OCP, 0x3f );
SX1276LoRaSetPAOutput( RFLR_PACONFIG_PASELECT_PABOOST );
SX1276LoRaSetPa20dBm( true );
LoRaSettings.Power = 20;
SX1276LoRaSetRFPower( LoRaSettings.Power );
}
#elif( MODULE_SX1276RF1JAS == 1 )
if( LoRaSettings.RFFrequency > 380000000 )
{
SX1276LoRaSetPAOutput( RFLR_PACONFIG_PASELECT_PABOOST );
SX1276LoRaSetPa20dBm( true );
LoRaSettings.Power = 20;
SX1276LoRaSetRFPower( LoRaSettings.Power );
}
else
{
SX1276LoRaSetPAOutput( RFLR_PACONFIG_PASELECT_RFO );
SX1276LoRaSetPa20dBm( false );
LoRaSettings.Power = 14;
SX1276LoRaSetRFPower( LoRaSettings.Power );
}
#endif
SX1276LoRaSetOpMode( RFLR_OPMODE_STANDBY );
SX1276ReadBuffer( REG_LR_OPMODE, SX1276Regs + 1, 0x70 - 1 );
}
void SX1276LoRaSetDefaults( void )
{
// REMARK: See SX1276 datasheet for modified default values.
// Sets IF frequency selection manual
SX1276Read( REG_LR_VERSION, &SX1276LR->RegVersion );
}
void SX1276LoRaReset( void )
{
uint32_t startTick;
SX1276SetReset( RADIO_RESET_ON );
// Wait 1ms
startTick = GET_TICK_COUNT( );
while( ( GET_TICK_COUNT( ) - startTick ) < TICK_RATE_MS( 1 ) );
SX1276SetReset( RADIO_RESET_OFF );
// Wait 6ms
startTick = GET_TICK_COUNT( );
while( ( GET_TICK_COUNT( ) - startTick ) < TICK_RATE_MS( 6 ) );
}
void SX1276LoRaSetOpMode( uint8_t opMode )
{
static uint8_t opModePrev = RFLR_OPMODE_STANDBY;
static bool antennaSwitchTxOnPrev = true;
bool antennaSwitchTxOn = false;
opModePrev = SX1276LR->RegOpMode & ~RFLR_OPMODE_MASK;
if( opMode != opModePrev )
{
if( opMode == RFLR_OPMODE_TRANSMITTER )
{
antennaSwitchTxOn = true;
}
else
{
antennaSwitchTxOn = false;
}
if( antennaSwitchTxOn != antennaSwitchTxOnPrev )
{
antennaSwitchTxOnPrev = antennaSwitchTxOn; // Antenna switch control
RXTX( antennaSwitchTxOn );
}
SX1276LR->RegOpMode = ( SX1276LR->RegOpMode & RFLR_OPMODE_MASK ) | opMode | RFLR_OPMODE_FREQMODE_ACCESS_LF;
SX1276Write( REG_LR_OPMODE, SX1276LR->RegOpMode );
}
}
uint8_t SX1276LoRaGetOpMode( void )
{
SX1276Read( REG_LR_OPMODE, &SX1276LR->RegOpMode );
return SX1276LR->RegOpMode & ~RFLR_OPMODE_MASK;
}
uint8_t SX1276LoRaReadRxGain( void )
{
SX1276Read( REG_LR_LNA, &SX1276LR->RegLna );
return( SX1276LR->RegLna >> 5 ) & 0x07;
}
double SX1276LoRaReadRssi( void )
{
// Reads the RSSI value
SX1276Read( REG_LR_RSSIVALUE, &SX1276LR->RegRssiValue );
if( LoRaSettings.RFFrequency < 860000000 )
{
return RssiOffsetLF[LoRaSettings.SignalBw] + ( double )SX1276LR->RegRssiValue;
}
else
{
return RssiOffsetHF[LoRaSettings.SignalBw] + ( double )SX1276LR->RegRssiValue;
}
}
uint8_t SX1276LoRaGetPacketRxGain( void )
{
return RxGain;
}
int8_t SX1276LoRaGetPacketSnr( void )
{
return RxPacketSnrEstimate;
}
double SX1276LoRaGetPacketRssi( void )
{
return RxPacketRssiValue;
}
void SX1276LoRaStartRx( void )
{
SX1276LoRaSetRFState( RFLR_STATE_RX_INIT );
}
void SX1276LoRaGetRxPacket( void *buffer, uint16_t *size )
{
*size = RxPacketSize;
RxPacketSize = 0;
memcpy( (void*)buffer, (void*)RFBuffer, (size_t)*size );
}
void SX1276LoRaSetTxPacket( const void *buffer, uint16_t size )
{
if( LoRaSettings.FreqHopOn == false )
{
TxPacketSize = size;
}
else
{
TxPacketSize = 255;
}
memcpy( ( void * )TFBuffer, buffer, ( size_t )TxPacketSize );
RFLRState = RFLR_STATE_TX_INIT;
}
uint8_t SX1276LoRaGetRFState( void )
{
return RFLRState;
}
void SX1276LoRaSetRFState( uint8_t state )
{
RFLRState = state;
}
/*!
* \brief Process the LoRa modem Rx and Tx state machines depending on the
* SX1276 operating mode.
*
* \retval rfState Current RF state [RF_IDLE, RF_BUSY,
* RF_RX_DONE, RF_RX_TIMEOUT,
* RF_TX_DONE, RF_TX_TIMEOUT]
*/
uint32_t SX1276LoRaProcess( void )
{
uint32_t result = RF_BUSY;
uint8_t regValue = 0;
switch( RFLRState )
{
case RFLR_STATE_IDLE:
break;
case RFLR_STATE_RX_INIT:
SX1276LoRaSetOpMode(RFLR_OPMODE_STANDBY);
SX1276LR->RegIrqFlagsMask = RFLR_IRQFLAGS_RXTIMEOUT |
//RFLR_IRQFLAGS_RXDONE |
RFLR_IRQFLAGS_PAYLOADCRCERROR |
RFLR_IRQFLAGS_VALIDHEADER |
RFLR_IRQFLAGS_TXDONE |
RFLR_IRQFLAGS_CADDONE |
RFLR_IRQFLAGS_FHSSCHANGEDCHANNEL |
RFLR_IRQFLAGS_CADDETECTED;
SX1276Write( REG_LR_IRQFLAGSMASK, SX1276LR->RegIrqFlagsMask );
if(LoRaSettings.FreqHopOn == true )
{
SX1276LR->RegHopPeriod = LoRaSettings.HopPeriod;
SX1276Read( REG_LR_HOPCHANNEL, &SX1276LR->RegHopChannel );
SX1276LoRaSetRFFrequency( HoppingFrequencies[SX1276LR->RegHopChannel & RFLR_HOPCHANNEL_CHANNEL_MASK] );
}
else
{
SX1276LR->RegHopPeriod = 255;
}
SX1276Write( REG_LR_HOPPERIOD, SX1276LR->RegHopPeriod );
if( LoRaSettings.RxSingleOn == true ) // Rx single mode
{
SX1276LoRaSetOpMode( RFLR_OPMODE_RECEIVER_SINGLE );
}
else // Rx continuous mode
{
SX1276LR->RegFifoAddrPtr = SX1276LR->RegFifoRxBaseAddr;
SX1276Write( REG_LR_FIFOADDRPTR, SX1276LR->RegFifoAddrPtr );
SX1276LoRaSetOpMode( RFLR_OPMODE_RECEIVER );
}
memset( RFBuffer, 0, ( size_t )RF_BUFFER_SIZE );
Rx_Time_Start=TickCounter;
PacketTimeout = LoRaSettings.RxPacketTimeout;
RxTimeoutTimer = GET_TICK_COUNT( );
RFLRState = RFLR_STATE_RX_RUNNING;
break;
case RFLR_STATE_RX_RUNNING:
SX1276Read(0x12, &regValue);
// RxDone
if(regValue & (1<<6))
{
RxTimeoutTimer = GET_TICK_COUNT( );
if( LoRaSettings.FreqHopOn == true )
{
SX1276Read( REG_LR_HOPCHANNEL, &SX1276LR->RegHopChannel );
SX1276LoRaSetRFFrequency( HoppingFrequencies[SX1276LR->RegHopChannel & RFLR_HOPCHANNEL_CHANNEL_MASK] );
}
// Clear Irq
SX1276Write( REG_LR_IRQFLAGS, RFLR_IRQFLAGS_RXDONE );
RFLRState = RFLR_STATE_RX_DONE;
}
// FHSS Changed Channel
if(regValue & (1<<1))
{
RxTimeoutTimer = GET_TICK_COUNT( );
if( LoRaSettings.FreqHopOn == true )
{
SX1276Read( REG_LR_HOPCHANNEL, &SX1276LR->RegHopChannel );
SX1276LoRaSetRFFrequency( HoppingFrequencies[SX1276LR->RegHopChannel & RFLR_HOPCHANNEL_CHANNEL_MASK] );
}
// Clear Irq
SX1276Write( REG_LR_IRQFLAGS, RFLR_IRQFLAGS_FHSSCHANGEDCHANNEL );
//RxGain = SX1276LoRaReadRxGain( );
}
if( LoRaSettings.RxSingleOn == true ) // Rx single mode
{
if( ( GET_TICK_COUNT( ) - RxTimeoutTimer ) > PacketTimeout )
{
RFLRState = RFLR_STATE_RX_TIMEOUT;
}
}
break;
case RFLR_STATE_RX_DONE:
SX1276Read( REG_LR_IRQFLAGS, &SX1276LR->RegIrqFlags );
if( ( SX1276LR->RegIrqFlags & RFLR_IRQFLAGS_PAYLOADCRCERROR ) == RFLR_IRQFLAGS_PAYLOADCRCERROR )
{
// Clear Irq
SX1276Write( REG_LR_IRQFLAGS, RFLR_IRQFLAGS_PAYLOADCRCERROR );
if( LoRaSettings.RxSingleOn == true ) // Rx single mode
{
RFLRState = RFLR_STATE_RX_INIT;
}
else
{
RFLRState = RFLR_STATE_RX_RUNNING;
}
break;
}
if( LoRaSettings.RxSingleOn == true ) // Rx single mode
{
SX1276LR->RegFifoAddrPtr = SX1276LR->RegFifoRxBaseAddr;
SX1276Write( REG_LR_FIFOADDRPTR, SX1276LR->RegFifoAddrPtr );
if( LoRaSettings.ImplicitHeaderOn == true )
{
RxPacketSize = SX1276LR->RegPayloadLength;
SX1276ReadFifo( RFBuffer, SX1276LR->RegPayloadLength );
}
else
{
SX1276Read( REG_LR_NBRXBYTES, &SX1276LR->RegNbRxBytes );
RxPacketSize = SX1276LR->RegNbRxBytes;
SX1276ReadFifo( RFBuffer, SX1276LR->RegNbRxBytes );
}
}
else // Rx continuous mode
{
SX1276Read( REG_LR_FIFORXCURRENTADDR, &SX1276LR->RegFifoRxCurrentAddr );
if( LoRaSettings.ImplicitHeaderOn == true )
{
RxPacketSize = SX1276LR->RegPayloadLength;
SX1276LR->RegFifoAddrPtr = SX1276LR->RegFifoRxCurrentAddr;
SX1276Write( REG_LR_FIFOADDRPTR, SX1276LR->RegFifoAddrPtr );
SX1276ReadFifo( RFBuffer, SX1276LR->RegPayloadLength );
}
else
{
SX1276Read( REG_LR_NBRXBYTES, &SX1276LR->RegNbRxBytes );
RxPacketSize = SX1276LR->RegNbRxBytes;
SX1276LR->RegFifoAddrPtr = SX1276LR->RegFifoRxCurrentAddr;
SX1276Write( REG_LR_FIFOADDRPTR, SX1276LR->RegFifoAddrPtr );
SX1276ReadFifo( RFBuffer, SX1276LR->RegNbRxBytes );
}
}
if( LoRaSettings.RxSingleOn == true ) // Rx single mode
{
RFLRState = RFLR_STATE_RX_INIT;
}
else // Rx continuous mode
{
RFLRState = RFLR_STATE_RX_RUNNING;
}
Rx_Time_End=TickCounter;
result = RF_RX_DONE;
break;
case RFLR_STATE_RX_TIMEOUT:
RFLRState = RFLR_STATE_RX_INIT;
result = RF_RX_TIMEOUT;
break;
case RFLR_STATE_TX_INIT:
Tx_Time_Start = TickCounter;
// Initializes the payload size
SX1276LR->RegPayloadLength = TxPacketSize;
SX1276Write( REG_LR_PAYLOADLENGTH, SX1276LR->RegPayloadLength );
SX1276LR->RegFifoTxBaseAddr = 0x00; // Full buffer used for Tx
SX1276Write( REG_LR_FIFOTXBASEADDR, SX1276LR->RegFifoTxBaseAddr );
SX1276LR->RegFifoAddrPtr = SX1276LR->RegFifoTxBaseAddr;
SX1276Write( REG_LR_FIFOADDRPTR, SX1276LR->RegFifoAddrPtr );
SX1276LoRaSetOpMode( RFLR_OPMODE_STANDBY );
// Write payload buffer to LORA modem
SX1276WriteFifo( TFBuffer, SX1276LR->RegPayloadLength );
if( LoRaSettings.FreqHopOn == true )
{
SX1276LR->RegIrqFlagsMask = RFLR_IRQFLAGS_RXTIMEOUT |
RFLR_IRQFLAGS_RXDONE |
RFLR_IRQFLAGS_PAYLOADCRCERROR |
RFLR_IRQFLAGS_VALIDHEADER |
//RFLR_IRQFLAGS_TXDONE |
RFLR_IRQFLAGS_CADDONE |
RFLR_IRQFLAGS_FHSSCHANGEDCHANNEL |
RFLR_IRQFLAGS_CADDETECTED;
SX1276LR->RegHopPeriod = LoRaSettings.HopPeriod;
SX1276Read( REG_LR_HOPCHANNEL, &SX1276LR->RegHopChannel );
SX1276LoRaSetRFFrequency( HoppingFrequencies[SX1276LR->RegHopChannel & RFLR_HOPCHANNEL_CHANNEL_MASK] );
}
else
{
SX1276LR->RegIrqFlagsMask = RFLR_IRQFLAGS_RXTIMEOUT |
RFLR_IRQFLAGS_RXDONE |
RFLR_IRQFLAGS_PAYLOADCRCERROR |
RFLR_IRQFLAGS_VALIDHEADER |
//RFLR_IRQFLAGS_TXDONE |
RFLR_IRQFLAGS_CADDONE |
RFLR_IRQFLAGS_FHSSCHANGEDCHANNEL |
RFLR_IRQFLAGS_CADDETECTED;
SX1276LR->RegHopPeriod = 0;
}
SX1276Write( REG_LR_HOPPERIOD, SX1276LR->RegHopPeriod );
SX1276Write( REG_LR_IRQFLAGSMASK, SX1276LR->RegIrqFlagsMask );
SX1276Write( REG_LR_DIOMAPPING1, ( regValue & RFLR_DIOMAPPING1_DIO0_MASK ) | RFLR_DIOMAPPING1_DIO0_01 );//DIO0设置为TXdone中断
SX1276LoRaSetOpMode( RFLR_OPMODE_TRANSMITTER );
RFLRState = RFLR_STATE_TX_RUNNING;
break;
case RFLR_STATE_TX_RUNNING:
SX1276Read(0x12, &regValue);
if(regValue & (1<<3))
{
// Clear Irq
SX1276Write( REG_LR_IRQFLAGS, RFLR_IRQFLAGS_TXDONE );
RFLRState = RFLR_STATE_TX_DONE;
}
// FHSS Changed Channel
if(regValue & (1<<3))
{
if( LoRaSettings.FreqHopOn == true )
{
SX1276Read( REG_LR_HOPCHANNEL, &SX1276LR->RegHopChannel );
SX1276LoRaSetRFFrequency( HoppingFrequencies[SX1276LR->RegHopChannel & RFLR_HOPCHANNEL_CHANNEL_MASK] );
}
// Clear Irq
SX1276Write( REG_LR_IRQFLAGS, RFLR_IRQFLAGS_FHSSCHANGEDCHANNEL );
}
break;
case RFLR_STATE_TX_DONE:
Tx_Time_End=TickCounter;
SX1276LoRaSetOpMode( RFLR_OPMODE_STANDBY );
RFLRState = RFLR_STATE_IDLE;
result = RF_TX_DONE;
break;
case RFLR_STATE_CAD_INIT:
// optimize the power consumption by switching off the transmitter as soon as the packet has been sent
SX1276LoRaSetOpMode( RFLR_OPMODE_STANDBY );
SX1276LR->RegIrqFlagsMask = RFLR_IRQFLAGS_RXTIMEOUT |
RFLR_IRQFLAGS_RXDONE |
RFLR_IRQFLAGS_PAYLOADCRCERROR |
RFLR_IRQFLAGS_VALIDHEADER |
RFLR_IRQFLAGS_TXDONE |
//RFLR_IRQFLAGS_CADDONE |
RFLR_IRQFLAGS_FHSSCHANGEDCHANNEL;
//RFLR_IRQFLAGS_CADDETECTED;
SX1276Write( REG_LR_IRQFLAGSMASK, SX1276LR->RegIrqFlagsMask );
SX1276LoRaSetOpMode( RFLR_OPMODE_CAD );
RFLRState = RFLR_STATE_CAD_RUNNING;
break;
case RFLR_STATE_CAD_RUNNING:
SX1276Read(0x12,&regValue);
int cad_done = regValue & (1<<2);
int cad_detected = regValue & (1<<0);
if( cad_done ) //CAD Done interrupt
{
SX1276Write( REG_LR_IRQFLAGS, RFLR_IRQFLAGS_CADDONE );
if( cad_detected ) // CAD Detected interrupt
{
SX1276Write( REG_LR_IRQFLAGS, RFLR_IRQFLAGS_CADDETECTED );
//CAD detected, we have a LoRa preamble
RFLRState = RFLR_STATE_RX_INIT;
result = RF_CHANNEL_ACTIVITY_DETECTED;
}
else
{
// The device goes in Standby Mode automatically
RFLRState = RFLR_STATE_IDLE;
result = RF_CHANNEL_EMPTY;
}
}
break;
default:
break;
}
return result;
}
uint32_t SX1276LoraChannelEmpty( void )
{
uint32_t result = 0;
RFLRState = RFLR_STATE_CAD_INIT;
SX1276LoRaProcess();
while(RFLRState == RFLR_STATE_CAD_RUNNING)
{
//KPrintf("\nLora--SX1276LoRaProcess()");
result = SX1276LoRaProcess();
}
if(result == RF_CHANNEL_EMPTY)
{
KPrintf("\nLora--RF_CHANNEL_EMPTY\n");
return 0;
}
else if(result == RF_CHANNEL_ACTIVITY_DETECTED)
{
KPrintf("\nLora--RF_CHANNEL_ACTIVITY_DETECTED\n");
return 1;
}
else
{
return 2;
}
}
#endif // USE_SX1276_RADIO
@@ -0,0 +1,820 @@
/*
* THE FOLLOWING FIRMWARE IS PROVIDED: (1) "AS IS" WITH NO WARRANTY; AND
* (2)TO ENABLE ACCESS TO CODING INFORMATION TO GUIDE AND FACILITATE CUSTOMER.
* CONSEQUENTLY, SEMTECH SHALL NOT BE HELD LIABLE FOR ANY DIRECT, INDIRECT OR
* CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE CONTENT
* OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING INFORMATION
* CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*
* Original Copyright (C) SEMTECH S.A.
* Modified Copyright (C) 2020 AIIT XUOS Lab
*/
/*!
* \file sx1276-LoRa.h
* \brief SX1276 RF chip driver mode LoRa
*
* \version 2.0.0
* \date Nov 21 2012
* \author Miguel Luis
*
* Last modified by Miguel Luis on Jun 19 2013
*/
/*************************************************
File name: sx1276-LoRa.h
Description: support aiit board configure and register function
History:
1. Date: 2021-04-25
Author: AIIT XUOS Lab
Modification:
1. replace original macro and basic date type with AIIT XUOS Lab's own defination
*************************************************/
#ifndef __SX1276_LORA_H__
#define __SX1276_LORA_H__
#include "stdint.h"
#include "stdbool.h"
//SX1276一些配置参数设置
typedef struct sLoRaSettings
{
uint32_t RFFrequency; //无线通信频率
int8_t Power; //功率
uint8_t SignalBw; //LORA 带宽[0: 7.8 kHz, 1: 10.4 kHz, 2: 15.6 kHz, 3: 20.8 kHz, 4: 31.2 kHz,
//5: 41.6 kHz, 6: 62.5 kHz, 7: 125 kHz, 8: 250 kHz, 9: 500 kHz, other: Reserved]
uint8_t SpreadingFactor; //扩频因子 LORA [6: 64, 7: 128, 8: 256, 9: 512, 10: 1024, 11: 2048, 12: 4096 chips]
uint8_t ErrorCoding; //LORA 纠错码 [1: 4/5, 2: 4/6, 3: 4/7, 4: 4/8]
bool CrcOn; //CRC效验开关 [0: OFF, 1: ON]
bool ImplicitHeaderOn; //隐藏头部信息开关 [0: OFF, 1: ON]
bool RxSingleOn; //接收单次模式\连续模式配置[0: Continuous, 1 Single]
bool FreqHopOn; //跳频模式开关 [0: OFF, 1: ON]
uint8_t HopPeriod; //跳频之间的周期长度 Hops every frequency hopping period symbols
uint32_t TxPacketTimeout; //最大发送时间
uint32_t RxPacketTimeout; //最大接收时间
uint8_t PayloadLength; //数据长度
}tLoRaSettings;
//RF数据包大小(模块配备了256Byte的RAM缓存,该缓存仅能通过LoRa模式访问)
#define RF_BUFFER_SIZE_MAX 256
#define RF_BUFFER_SIZE 256
//LoRa的返回值
typedef enum
{
RFLR_STATE_IDLE,
RFLR_STATE_RX_INIT,
RFLR_STATE_RX_RUNNING,
RFLR_STATE_RX_DONE,
RFLR_STATE_RX_TIMEOUT,
RFLR_STATE_TX_INIT,
RFLR_STATE_TX_RUNNING,
RFLR_STATE_TX_DONE,
RFLR_STATE_TX_TIMEOUT,
RFLR_STATE_CAD_INIT,
RFLR_STATE_CAD_RUNNING,
}tRFLRStates;
//SX1276 definitions
#define XTAL_FREQ 32000000
#define FREQ_STEP 61.03515625
/*LoRa模式寄存器映射*/
//SX1276内部寄存器地址
#define REG_LR_FIFO 0x00 //FIFO 数据输入/输出。当器件处于睡眠模式时,FIFO被清零,无法访问。
//通用寄存器
#define REG_LR_OPMODE 0x01 //关于模式选择相关的寄存器
#define REG_LR_BANDSETTING 0x04
#define REG_LR_FRFMSB 0x06 //RF 载波频率最高有效位
#define REG_LR_FRFMID 0x07 //RF 载波频率中间有效位
#define REG_LR_FRFLSB 0x08 //RF 载波频率最低有效位
//RF模块寄存器
#define REG_LR_PACONFIG 0x09
#define REG_LR_PARAMP 0x0A
#define REG_LR_OCP 0x0B
#define REG_LR_LNA 0x0C
//LoRa页面寄存器
#define REG_LR_FIFOADDRPTR 0x0D
#define REG_LR_FIFOTXBASEADDR 0x0E
#define REG_LR_FIFORXBASEADDR 0x0F
#define REG_LR_FIFORXCURRENTADDR 0x10
#define REG_LR_IRQFLAGSMASK 0x11 //IAQ标志屏蔽
#define REG_LR_IRQFLAGS 0x12
#define REG_LR_NBRXBYTES 0x13
#define REG_LR_RXHEADERCNTVALUEMSB 0x14
#define REG_LR_RXHEADERCNTVALUELSB 0x15
#define REG_LR_RXPACKETCNTVALUEMSB 0x16
#define REG_LR_RXPACKETCNTVALUELSB 0x17
#define REG_LR_MODEMSTAT 0x18
#define REG_LR_PKTSNRVALUE 0x19
#define REG_LR_PKTRSSIVALUE 0x1A
#define REG_LR_RSSIVALUE 0x1B
#define REG_LR_HOPCHANNEL 0x1C
#define REG_LR_MODEMCONFIG1 0x1D
#define REG_LR_MODEMCONFIG2 0x1E
#define REG_LR_SYMBTIMEOUTLSB 0x1F
#define REG_LR_PREAMBLEMSB 0x20
#define REG_LR_PREAMBLELSB 0x21
#define REG_LR_PAYLOADLENGTH 0x22
#define REG_LR_PAYLOADMAXLENGTH 0x23
#define REG_LR_HOPPERIOD 0x24
#define REG_LR_FIFORXBYTEADDR 0x25
#define REG_LR_MODEMCONFIG3 0x26
/*以上是LoRa模式寄存器映射*/
//IO控制寄存器(关于DI00-DI05的映射设置)
#define REG_LR_DIOMAPPING1 0x40
#define REG_LR_DIOMAPPING2 0x41
//版本寄存器
#define REG_LR_VERSION 0x42
//附加寄存器
#define REG_LR_PLLHOP 0x44
#define REG_LR_TCXO 0x4B
#define REG_LR_PADAC 0x4D
#define REG_LR_FORMERTEMP 0x5B
#define REG_LR_BITRATEFRAC 0x5D
#define REG_LR_AGCREF 0x61
#define REG_LR_AGCTHRESH1 0x62
#define REG_LR_AGCTHRESH2 0x63
#define REG_LR_AGCTHRESH3 0x64
//与模式选择相关的宏定义 RegOpMode(寄存器地址0X01)
#define RFLR_OPMODE_LONGRANGEMODE_MASK 0x7F
#define RFLR_OPMODE_LONGRANGEMODE_OFF 0x00 // Default
#define RFLR_OPMODE_LONGRANGEMODE_ON 0x80
#define RFLR_OPMODE_ACCESSSHAREDREG_MASK 0xBF
#define RFLR_OPMODE_ACCESSSHAREDREG_ENABLE 0x40
#define RFLR_OPMODE_ACCESSSHAREDREG_DISABLE 0x00 // Default
#define RFLR_OPMODE_FREQMODE_ACCESS_MASK 0xF7
#define RFLR_OPMODE_FREQMODE_ACCESS_LF 0x08 // Default
#define RFLR_OPMODE_FREQMODE_ACCESS_HF 0x00
#define RFLR_OPMODE_MASK 0xF8
#define RFLR_OPMODE_SLEEP 0x00 //睡眠模式
#define RFLR_OPMODE_STANDBY 0x01 //待机模式
#define RFLR_OPMODE_SYNTHESIZER_TX 0x02 //频率合成器转换至Tx频率
#define RFLR_OPMODE_TRANSMITTER 0x03 //发送模式
#define RFLR_OPMODE_SYNTHESIZER_RX 0x04 //频率合成器转换至Rx频率
#define RFLR_OPMODE_RECEIVER 0x05 //接收模式
#define RFLR_OPMODE_RECEIVER_SINGLE 0x06 //单次接收模式
#define RFLR_OPMODE_CAD 0x07 //CAD模式
//与位带操作相关的宏定义
#define RFLR_BANDSETTING_MASK 0x3F
#define RFLR_BANDSETTING_AUTO 0x00 // Default
#define RFLR_BANDSETTING_DIV_BY_1 0x40
#define RFLR_BANDSETTING_DIV_BY_2 0x80
#define RFLR_BANDSETTING_DIV_BY_6 0xC0
//射频载波频率设置相关宏定义 RegFrf (MHz)(寄存器地址0x060x07,0x08)
#define RFLR_FRFMSB_434_MHZ 0x6C // Default
#define RFLR_FRFMID_434_MHZ 0x80 // Default
#define RFLR_FRFLSB_434_MHZ 0x00 // Default
#define RFLR_FRFMSB_470_MHZ 0x73 // Default
#define RFLR_FRFMID_470_MHZ 0xBB // Default
#define RFLR_FRFLSB_470_MHZ 0xBB // Default
#define RFLR_FRFMSB_863_MHZ 0xD7
#define RFLR_FRFMID_863_MHZ 0xC0
#define RFLR_FRFLSB_863_MHZ 0x00
#define RFLR_FRFMSB_864_MHZ 0xD8
#define RFLR_FRFMID_864_MHZ 0x00
#define RFLR_FRFLSB_864_MHZ 0x00
#define RFLR_FRFMSB_865_MHZ 0xD8
#define RFLR_FRFMID_865_MHZ 0x40
#define RFLR_FRFLSB_865_MHZ 0x00
#define RFLR_FRFMSB_866_MHZ 0xD8
#define RFLR_FRFMID_866_MHZ 0x80
#define RFLR_FRFLSB_866_MHZ 0x00
#define RFLR_FRFMSB_867_MHZ 0xD8
#define RFLR_FRFMID_867_MHZ 0xC0
#define RFLR_FRFLSB_867_MHZ 0x00
#define RFLR_FRFMSB_868_MHZ 0xD9
#define RFLR_FRFMID_868_MHZ 0x00
#define RFLR_FRFLSB_868_MHZ 0x00
#define RFLR_FRFMSB_869_MHZ 0xD9
#define RFLR_FRFMID_869_MHZ 0x40
#define RFLR_FRFLSB_869_MHZ 0x00
#define RFLR_FRFMSB_870_MHZ 0xD9
#define RFLR_FRFMID_870_MHZ 0x80
#define RFLR_FRFLSB_870_MHZ 0x00
#define RFLR_FRFMSB_902_MHZ 0xE1
#define RFLR_FRFMID_902_MHZ 0x80
#define RFLR_FRFLSB_902_MHZ 0x00
#define RFLR_FRFMSB_903_MHZ 0xE1
#define RFLR_FRFMID_903_MHZ 0xC0
#define RFLR_FRFLSB_903_MHZ 0x00
#define RFLR_FRFMSB_904_MHZ 0xE2
#define RFLR_FRFMID_904_MHZ 0x00
#define RFLR_FRFLSB_904_MHZ 0x00
#define RFLR_FRFMSB_905_MHZ 0xE2
#define RFLR_FRFMID_905_MHZ 0x40
#define RFLR_FRFLSB_905_MHZ 0x00
#define RFLR_FRFMSB_906_MHZ 0xE2
#define RFLR_FRFMID_906_MHZ 0x80
#define RFLR_FRFLSB_906_MHZ 0x00
#define RFLR_FRFMSB_907_MHZ 0xE2
#define RFLR_FRFMID_907_MHZ 0xC0
#define RFLR_FRFLSB_907_MHZ 0x00
#define RFLR_FRFMSB_908_MHZ 0xE3
#define RFLR_FRFMID_908_MHZ 0x00
#define RFLR_FRFLSB_908_MHZ 0x00
#define RFLR_FRFMSB_909_MHZ 0xE3
#define RFLR_FRFMID_909_MHZ 0x40
#define RFLR_FRFLSB_909_MHZ 0x00
#define RFLR_FRFMSB_910_MHZ 0xE3
#define RFLR_FRFMID_910_MHZ 0x80
#define RFLR_FRFLSB_910_MHZ 0x00
#define RFLR_FRFMSB_911_MHZ 0xE3
#define RFLR_FRFMID_911_MHZ 0xC0
#define RFLR_FRFLSB_911_MHZ 0x00
#define RFLR_FRFMSB_912_MHZ 0xE4
#define RFLR_FRFMID_912_MHZ 0x00
#define RFLR_FRFLSB_912_MHZ 0x00
#define RFLR_FRFMSB_913_MHZ 0xE4
#define RFLR_FRFMID_913_MHZ 0x40
#define RFLR_FRFLSB_913_MHZ 0x00
#define RFLR_FRFMSB_914_MHZ 0xE4
#define RFLR_FRFMID_914_MHZ 0x80
#define RFLR_FRFLSB_914_MHZ 0x00
#define RFLR_FRFMSB_915_MHZ 0xE4 // Default
#define RFLR_FRFMID_915_MHZ 0xC0 // Default
#define RFLR_FRFLSB_915_MHZ 0x00 // Default
#define RFLR_FRFMSB_916_MHZ 0xE5
#define RFLR_FRFMID_916_MHZ 0x00
#define RFLR_FRFLSB_916_MHZ 0x00
#define RFLR_FRFMSB_917_MHZ 0xE5
#define RFLR_FRFMID_917_MHZ 0x40
#define RFLR_FRFLSB_917_MHZ 0x00
#define RFLR_FRFMSB_918_MHZ 0xE5
#define RFLR_FRFMID_918_MHZ 0x80
#define RFLR_FRFLSB_918_MHZ 0x00
#define RFLR_FRFMSB_919_MHZ 0xE5
#define RFLR_FRFMID_919_MHZ 0xC0
#define RFLR_FRFLSB_919_MHZ 0x00
#define RFLR_FRFMSB_920_MHZ 0xE6
#define RFLR_FRFMID_920_MHZ 0x00
#define RFLR_FRFLSB_920_MHZ 0x00
#define RFLR_FRFMSB_921_MHZ 0xE6
#define RFLR_FRFMID_921_MHZ 0x40
#define RFLR_FRFLSB_921_MHZ 0x00
#define RFLR_FRFMSB_922_MHZ 0xE6
#define RFLR_FRFMID_922_MHZ 0x80
#define RFLR_FRFLSB_922_MHZ 0x00
#define RFLR_FRFMSB_923_MHZ 0xE6
#define RFLR_FRFMID_923_MHZ 0xC0
#define RFLR_FRFLSB_923_MHZ 0x00
#define RFLR_FRFMSB_924_MHZ 0xE7
#define RFLR_FRFMID_924_MHZ 0x00
#define RFLR_FRFLSB_924_MHZ 0x00
#define RFLR_FRFMSB_925_MHZ 0xE7
#define RFLR_FRFMID_925_MHZ 0x40
#define RFLR_FRFLSB_925_MHZ 0x00
#define RFLR_FRFMSB_926_MHZ 0xE7
#define RFLR_FRFMID_926_MHZ 0x80
#define RFLR_FRFLSB_926_MHZ 0x00
#define RFLR_FRFMSB_927_MHZ 0xE7
#define RFLR_FRFMID_927_MHZ 0xC0
#define RFLR_FRFLSB_927_MHZ 0x00
#define RFLR_FRFMSB_928_MHZ 0xE8
#define RFLR_FRFMID_928_MHZ 0x00
#define RFLR_FRFLSB_928_MHZ 0x00
//PA(功率放大器) 选择和输出功率控制设置相关宏定义 RegPaConfig(寄存器地址0X09
#define RFLR_PACONFIG_PASELECT_MASK 0x7F
#define RFLR_PACONFIG_PASELECT_PABOOST 0x80
#define RFLR_PACONFIG_PASELECT_RFO 0x00 // Default
#define RFLR_PACONFIG_MAX_POWER_MASK 0x8F
#define RFLR_PACONFIG_OUTPUTPOWER_MASK 0xF0
//PA(功率放大器) 斜升/斜降时间和低相噪设置相关定义 RegPaRamp(寄存器地址0X0A
#define RFLR_PARAMP_TXBANDFORCE_MASK 0xEF
#define RFLR_PARAMP_TXBANDFORCE_BAND_SEL 0x10
#define RFLR_PARAMP_TXBANDFORCE_AUTO 0x00 // Default
#define RFLR_PARAMP_MASK 0xF0
#define RFLR_PARAMP_3400_US 0x00
#define RFLR_PARAMP_2000_US 0x01
#define RFLR_PARAMP_1000_US 0x02
#define RFLR_PARAMP_0500_US 0x03
#define RFLR_PARAMP_0250_US 0x04
#define RFLR_PARAMP_0125_US 0x05
#define RFLR_PARAMP_0100_US 0x06
#define RFLR_PARAMP_0062_US 0x07
#define RFLR_PARAMP_0050_US 0x08
#define RFLR_PARAMP_0040_US 0x09 // Default
#define RFLR_PARAMP_0031_US 0x0A
#define RFLR_PARAMP_0025_US 0x0B
#define RFLR_PARAMP_0020_US 0x0C
#define RFLR_PARAMP_0015_US 0x0D
#define RFLR_PARAMP_0012_US 0x0E
#define RFLR_PARAMP_0010_US 0x0F
//过流保护控制设置相关宏定义 RegOcp(寄存器地址0X0B
#define RFLR_OCP_MASK 0xDF
#define RFLR_OCP_ON 0x20 // Default
#define RFLR_OCP_OFF 0x00
#define RFLR_OCP_TRIM_MASK 0xE0
#define RFLR_OCP_TRIM_045_MA 0x00
#define RFLR_OCP_TRIM_050_MA 0x01
#define RFLR_OCP_TRIM_055_MA 0x02
#define RFLR_OCP_TRIM_060_MA 0x03
#define RFLR_OCP_TRIM_065_MA 0x04
#define RFLR_OCP_TRIM_070_MA 0x05
#define RFLR_OCP_TRIM_075_MA 0x06
#define RFLR_OCP_TRIM_080_MA 0x07
#define RFLR_OCP_TRIM_085_MA 0x08
#define RFLR_OCP_TRIM_090_MA 0x09
#define RFLR_OCP_TRIM_095_MA 0x0A
#define RFLR_OCP_TRIM_100_MA 0x0B // Default
#define RFLR_OCP_TRIM_105_MA 0x0C
#define RFLR_OCP_TRIM_110_MA 0x0D
#define RFLR_OCP_TRIM_115_MA 0x0E
#define RFLR_OCP_TRIM_120_MA 0x0F
#define RFLR_OCP_TRIM_130_MA 0x10
#define RFLR_OCP_TRIM_140_MA 0x11
#define RFLR_OCP_TRIM_150_MA 0x12
#define RFLR_OCP_TRIM_160_MA 0x13
#define RFLR_OCP_TRIM_170_MA 0x14
#define RFLR_OCP_TRIM_180_MA 0x15
#define RFLR_OCP_TRIM_190_MA 0x16
#define RFLR_OCP_TRIM_200_MA 0x17
#define RFLR_OCP_TRIM_210_MA 0x18
#define RFLR_OCP_TRIM_220_MA 0x19
#define RFLR_OCP_TRIM_230_MA 0x1A
#define RFLR_OCP_TRIM_240_MA 0x1B
//LNA(低噪声放大器 )设置相关宏定义 RegLna(寄存器地址0X0C
#define RFLR_LNA_GAIN_MASK 0x1F
#define RFLR_LNA_GAIN_G1 0x20 // Default
#define RFLR_LNA_GAIN_G2 0x40
#define RFLR_LNA_GAIN_G3 0x60
#define RFLR_LNA_GAIN_G4 0x80
#define RFLR_LNA_GAIN_G5 0xA0
#define RFLR_LNA_GAIN_G6 0xC0
#define RFLR_LNA_BOOST_LF_MASK 0xE7
#define RFLR_LNA_BOOST_LF_DEFAULT 0x00 // Default
#define RFLR_LNA_BOOST_LF_GAIN 0x08
#define RFLR_LNA_BOOST_LF_IP3 0x10
#define RFLR_LNA_BOOST_LF_BOOST 0x18
#define RFLR_LNA_RXBANDFORCE_MASK 0xFB
#define RFLR_LNA_RXBANDFORCE_BAND_SEL 0x04
#define RFLR_LNA_RXBANDFORCE_AUTO 0x00 // Default
#define RFLR_LNA_BOOST_HF_MASK 0xFC
#define RFLR_LNA_BOOST_HF_OFF 0x00 // Default
#define RFLR_LNA_BOOST_HF_ON 0x03
//FIFO 数据缓冲区中 SPI 接口地址指针(寄存器地址0X0D)
#define RFLR_FIFOADDRPTR 0x00 // Default
//发送信息的起始位置
#define RFLR_FIFOTXBASEADDR 0x80 // Default
//接收信息的起始位置
#define RFLR_FIFORXBASEADDR 0x00 // Default
/*!
* RegFifoRxCurrentAddr (Read Only)
*/
//关于中断屏蔽相关的宏定义
#define RFLR_IRQFLAGS_RXTIMEOUT_MASK 0x80
#define RFLR_IRQFLAGS_RXDONE_MASK 0x40
#define RFLR_IRQFLAGS_PAYLOADCRCERROR_MASK 0x20
#define RFLR_IRQFLAGS_VALIDHEADER_MASK 0x10
#define RFLR_IRQFLAGS_TXDONE_MASK 0x08
#define RFLR_IRQFLAGS_CADDONE_MASK 0x04
#define RFLR_IRQFLAGS_FHSSCHANGEDCHANNEL_MASK 0x02
#define RFLR_IRQFLAGS_CADDETECTED_MASK 0x01
//关于中断打开相关的宏定义
#define RFLR_IRQFLAGS_RXTIMEOUT 0x80
#define RFLR_IRQFLAGS_RXDONE 0x40
#define RFLR_IRQFLAGS_PAYLOADCRCERROR 0x20
#define RFLR_IRQFLAGS_VALIDHEADER 0x10
#define RFLR_IRQFLAGS_TXDONE 0x08
#define RFLR_IRQFLAGS_CADDONE 0x04
#define RFLR_IRQFLAGS_FHSSCHANGEDCHANNEL 0x02
#define RFLR_IRQFLAGS_CADDETECTED 0x01
/*!
* RegFifoRxNbBytes (Read Only) //
*/
/*!
* RegRxHeaderCntValueMsb (Read Only) //
*/
/*!
* RegRxHeaderCntValueLsb (Read Only) //
*/
/*!
* RegRxPacketCntValueMsb (Read Only) //
*/
/*!
* RegRxPacketCntValueLsb (Read Only) //
*/
/*!
* RegModemStat (Read Only) //
*/
#define RFLR_MODEMSTAT_RX_CR_MASK 0x1F
#define RFLR_MODEMSTAT_MODEM_STATUS_MASK 0xE0
/*!
* RegPktSnrValue (Read Only) //
*/
/*!
* RegPktRssiValue (Read Only) //
*/
/*!
* RegRssiValue (Read Only) //
*/
//与信号宽度,纠错编码率,是否显示报头有关宏定义(寄存器位置0X1D)
#define RFLR_MODEMCONFIG1_BW_MASK 0x0F
#define RFLR_MODEMCONFIG1_BW_7_81_KHZ 0x00
#define RFLR_MODEMCONFIG1_BW_10_41_KHZ 0x10
#define RFLR_MODEMCONFIG1_BW_15_62_KHZ 0x20
#define RFLR_MODEMCONFIG1_BW_20_83_KHZ 0x30
#define RFLR_MODEMCONFIG1_BW_31_25_KHZ 0x40
#define RFLR_MODEMCONFIG1_BW_41_66_KHZ 0x50
#define RFLR_MODEMCONFIG1_BW_62_50_KHZ 0x60
#define RFLR_MODEMCONFIG1_BW_125_KHZ 0x70 // Default
#define RFLR_MODEMCONFIG1_BW_250_KHZ 0x80
#define RFLR_MODEMCONFIG1_BW_500_KHZ 0x90
#define RFLR_MODEMCONFIG1_CODINGRATE_MASK 0xF1
#define RFLR_MODEMCONFIG1_CODINGRATE_4_5 0x02
#define RFLR_MODEMCONFIG1_CODINGRATE_4_6 0x04 // Default
#define RFLR_MODEMCONFIG1_CODINGRATE_4_7 0x06
#define RFLR_MODEMCONFIG1_CODINGRATE_4_8 0x08
#define RFLR_MODEMCONFIG1_IMPLICITHEADER_MASK 0xFE
#define RFLR_MODEMCONFIG1_IMPLICITHEADER_ON 0x01
#define RFLR_MODEMCONFIG1_IMPLICITHEADER_OFF 0x00 // Default
//与扩频因子,接收模式,发送CRC开启,RX超时相关宏定义
#define RFLR_MODEMCONFIG2_SF_MASK 0x0F
#define RFLR_MODEMCONFIG2_SF_6 0x60
#define RFLR_MODEMCONFIG2_SF_7 0x70 // Default
#define RFLR_MODEMCONFIG2_SF_8 0x80
#define RFLR_MODEMCONFIG2_SF_9 0x90
#define RFLR_MODEMCONFIG2_SF_10 0xA0
#define RFLR_MODEMCONFIG2_SF_11 0xB0
#define RFLR_MODEMCONFIG2_SF_12 0xC0
#define RFLR_MODEMCONFIG2_TXCONTINUOUSMODE_MASK 0xF7
#define RFLR_MODEMCONFIG2_TXCONTINUOUSMODE_ON 0x08
#define RFLR_MODEMCONFIG2_TXCONTINUOUSMODE_OFF 0x00
#define RFLR_MODEMCONFIG2_RXPAYLOADCRC_MASK 0xFB
#define RFLR_MODEMCONFIG2_RXPAYLOADCRC_ON 0x04
#define RFLR_MODEMCONFIG2_RXPAYLOADCRC_OFF 0x00 // Default
#define RFLR_MODEMCONFIG2_SYMBTIMEOUTMSB_MASK 0xFC
#define RFLR_MODEMCONFIG2_SYMBTIMEOUTMSB 0x00 // Default
/*!
* RegHopChannel (Read Only)
*/
#define RFLR_HOPCHANNEL_PLL_LOCK_TIMEOUT_MASK 0x7F
#define RFLR_HOPCHANNEL_PLL_LOCK_FAIL 0x80
#define RFLR_HOPCHANNEL_PLL_LOCK_SUCCEED 0x00 // Default
#define RFLR_HOPCHANNEL_PAYLOAD_CRC16_MASK 0xBF
#define RFLR_HOPCHANNEL_PAYLOAD_CRC16_ON 0x40
#define RFLR_HOPCHANNEL_PAYLOAD_CRC16_OFF 0x00 // Default
#define RFLR_HOPCHANNEL_CHANNEL_MASK 0x3F
/*!
* RegSymbTimeoutLsb
*/
#define RFLR_SYMBTIMEOUTLSB_SYMBTIMEOUT 0x64 // Default
/*!
* RegPreambleLengthMsb
*/
#define RFLR_PREAMBLELENGTHMSB 0x00 // Default
/*!
* RegPreambleLengthLsb
*/
#define RFLR_PREAMBLELENGTHLSB 0x08 // Default
/*!
* RegPayloadLength
*/
#define RFLR_PAYLOADLENGTH 0x0E // Default
/*!
* RegPayloadMaxLength
*/
#define RFLR_PAYLOADMAXLENGTH 0xFF // Default
/*!
* RegHopPeriod
*/
#define RFLR_HOPPERIOD_FREQFOPPINGPERIOD 0x00 // Default
/*!
* RegDioMapping1
*/
#define RFLR_DIOMAPPING1_DIO0_MASK 0x3F
#define RFLR_DIOMAPPING1_DIO0_00 0x00 // Default
#define RFLR_DIOMAPPING1_DIO0_01 0x40
#define RFLR_DIOMAPPING1_DIO0_10 0x80
#define RFLR_DIOMAPPING1_DIO0_11 0xC0
#define RFLR_DIOMAPPING1_DIO1_MASK 0xCF
#define RFLR_DIOMAPPING1_DIO1_00 0x00 // Default
#define RFLR_DIOMAPPING1_DIO1_01 0x10
#define RFLR_DIOMAPPING1_DIO1_10 0x20
#define RFLR_DIOMAPPING1_DIO1_11 0x30
#define RFLR_DIOMAPPING1_DIO2_MASK 0xF3
#define RFLR_DIOMAPPING1_DIO2_00 0x00 // Default
#define RFLR_DIOMAPPING1_DIO2_01 0x04
#define RFLR_DIOMAPPING1_DIO2_10 0x08
#define RFLR_DIOMAPPING1_DIO2_11 0x0C
#define RFLR_DIOMAPPING1_DIO3_MASK 0xFC
#define RFLR_DIOMAPPING1_DIO3_00 0x00 // Default
#define RFLR_DIOMAPPING1_DIO3_01 0x01
#define RFLR_DIOMAPPING1_DIO3_10 0x02
#define RFLR_DIOMAPPING1_DIO3_11 0x03
/*!
* RegDioMapping2
*/
#define RFLR_DIOMAPPING2_DIO4_MASK 0x3F
#define RFLR_DIOMAPPING2_DIO4_00 0x00 // Default
#define RFLR_DIOMAPPING2_DIO4_01 0x40
#define RFLR_DIOMAPPING2_DIO4_10 0x80
#define RFLR_DIOMAPPING2_DIO4_11 0xC0
#define RFLR_DIOMAPPING2_DIO5_MASK 0xCF
#define RFLR_DIOMAPPING2_DIO5_00 0x00 // Default
#define RFLR_DIOMAPPING2_DIO5_01 0x10
#define RFLR_DIOMAPPING2_DIO5_10 0x20
#define RFLR_DIOMAPPING2_DIO5_11 0x30
#define RFLR_DIOMAPPING2_MAP_MASK 0xFE
#define RFLR_DIOMAPPING2_MAP_PREAMBLEDETECT 0x01
#define RFLR_DIOMAPPING2_MAP_RSSI 0x00 // Default
/*!
* RegVersion (Read Only)
*/
/*!
* RegAgcRef
*/
/*!
* RegAgcThresh1
*/
/*!
* RegAgcThresh2
*/
/*!
* RegAgcThresh3
*/
/*!
* RegFifoRxByteAddr (Read Only)
*/
/*!
* RegPllHop
*/
#define RFLR_PLLHOP_FASTHOP_MASK 0x7F
#define RFLR_PLLHOP_FASTHOP_ON 0x80
#define RFLR_PLLHOP_FASTHOP_OFF 0x00 // Default
/*!
* RegTcxo
*/
#define RFLR_TCXO_TCXOINPUT_MASK 0xEF
#define RFLR_TCXO_TCXOINPUT_ON 0x10
#define RFLR_TCXO_TCXOINPUT_OFF 0x00 // Default
/*!
* RegPaDac
*/
#define RFLR_PADAC_20DBM_MASK 0xF8
#define RFLR_PADAC_20DBM_ON 0x07
#define RFLR_PADAC_20DBM_OFF 0x04 // Default
/*!
* RegPll
*/
#define RFLR_PLL_BANDWIDTH_MASK 0x3F
#define RFLR_PLL_BANDWIDTH_75 0x00
#define RFLR_PLL_BANDWIDTH_150 0x40
#define RFLR_PLL_BANDWIDTH_225 0x80
#define RFLR_PLL_BANDWIDTH_300 0xC0 // Default
/*!
* RegPllLowPn
*/
#define RFLR_PLLLOWPN_BANDWIDTH_MASK 0x3F
#define RFLR_PLLLOWPN_BANDWIDTH_75 0x00
#define RFLR_PLLLOWPN_BANDWIDTH_150 0x40
#define RFLR_PLLLOWPN_BANDWIDTH_225 0x80
#define RFLR_PLLLOWPN_BANDWIDTH_300 0xC0 // Default
/*!
* RegModemConfig3
*/
#define RFLR_MODEMCONFIG3_LOWDATARATEOPTIMIZE_MASK 0xF7
#define RFLR_MODEMCONFIG3_LOWDATARATEOPTIMIZE_ON 0x08
#define RFLR_MODEMCONFIG3_LOWDATARATEOPTIMIZE_OFF 0x00 // Default
#define RFLR_MODEMCONFIG3_AGCAUTO_MASK 0xFB
#define RFLR_MODEMCONFIG3_AGCAUTO_ON 0x04 // Default
#define RFLR_MODEMCONFIG3_AGCAUTO_OFF 0x00
/*!
* RegFormerTemp
*/
typedef struct sSX1276LR
{
uint8_t RegFifo; // 0x00
// Common settings
uint8_t RegOpMode; // 0x01
uint8_t RegRes02; // 0x02
uint8_t RegRes03; // 0x03
uint8_t RegBandSetting; // 0x04
uint8_t RegRes05; // 0x05
uint8_t RegFrfMsb; // 0x06
uint8_t RegFrfMid; // 0x07
uint8_t RegFrfLsb; // 0x08
// Tx settings
uint8_t RegPaConfig; // 0x09
uint8_t RegPaRamp; // 0x0A
uint8_t RegOcp; // 0x0B
// Rx settings
uint8_t RegLna; // 0x0C
// LoRa registers
uint8_t RegFifoAddrPtr; // 0x0D
uint8_t RegFifoTxBaseAddr; // 0x0E
uint8_t RegFifoRxBaseAddr; // 0x0F
uint8_t RegFifoRxCurrentAddr; // 0x10
uint8_t RegIrqFlagsMask; // 0x11
uint8_t RegIrqFlags; // 0x12
uint8_t RegNbRxBytes; // 0x13
uint8_t RegRxHeaderCntValueMsb; // 0x14
uint8_t RegRxHeaderCntValueLsb; // 0x15
uint8_t RegRxPacketCntValueMsb; // 0x16
uint8_t RegRxPacketCntValueLsb; // 0x17
uint8_t RegModemStat; // 0x18
uint8_t RegPktSnrValue; // 0x19
uint8_t RegPktRssiValue; // 0x1A
uint8_t RegRssiValue; // 0x1B
uint8_t RegHopChannel; // 0x1C
uint8_t RegModemConfig1; // 0x1D
uint8_t RegModemConfig2; // 0x1E
uint8_t RegSymbTimeoutLsb; // 0x1F
uint8_t RegPreambleMsb; // 0x20
uint8_t RegPreambleLsb; // 0x21
uint8_t RegPayloadLength; // 0x22
uint8_t RegMaxPayloadLength; // 0x23
uint8_t RegHopPeriod; // 0x24 跳频周期
uint8_t RegFifoRxByteAddr; // 0x25
uint8_t RegModemConfig3; // 0x26
uint8_t RegTestReserved27[0x30 - 0x27]; // 0x27-0x30
uint8_t RegTestReserved31; // 0x31
uint8_t RegTestReserved32[0x40 - 0x32]; // 0x32-0x40
// I/O settings
uint8_t RegDioMapping1; // 0x40
uint8_t RegDioMapping2; // 0x41
// Version
uint8_t RegVersion; // 0x42
// Additional settings
uint8_t RegAgcRef; // 0x43
uint8_t RegAgcThresh1; // 0x44
uint8_t RegAgcThresh2; // 0x45
uint8_t RegAgcThresh3; // 0x46
// Test
uint8_t RegTestReserved47[0x4B - 0x47]; // 0x47-0x4A
// Additional settings
uint8_t RegPllHop; // 0x4B
uint8_t RegTestReserved4C; // 0x4C
uint8_t RegPaDac; // 0x4D
// Test
uint8_t RegTestReserved4E[0x58-0x4E]; // 0x4E-0x57
// Additional settings
uint8_t RegTcxo; // 0x58
// Test
uint8_t RegTestReserved59; // 0x59
// Test
uint8_t RegTestReserved5B; // 0x5B
// Additional settings
uint8_t RegPll; // 0x5C
// Test
uint8_t RegTestReserved5D; // 0x5D
// Additional settings
uint8_t RegPllLowPn; // 0x5E
// Test
uint8_t RegTestReserved5F[0x6C - 0x5F]; // 0x5F-0x6B
// Additional settings
uint8_t RegFormerTemp; // 0x6C
// Test
uint8_t RegTestReserved6D[0x71 - 0x6D]; // 0x6D-0x70
}tSX1276LR;
extern tSX1276LR* SX1276LR;
//初始化SX1276LoRa模式
void SX1276LoRaInit( void );
//读SX1276的版本号
void SX1276LoRaSetDefaults( void );
//启用/禁用LoRa模式
void SX1276LoRaSetLoRaOn( bool enable );
//设置SX1276操作模式
void SX1276LoRaSetOpMode( uint8_t opMode );
//获取SX1276操作模式
uint8_t SX1276LoRaGetOpMode( void );
//读取SX1276低噪声放大器(信号放大)的增益,
uint8_t SX1276LoRaReadRxGain( void );
//读取lora模式下无线信号强度
double SX1276LoRaReadRssi( void );
//获取数据时的增益值
uint8_t SX1276LoRaGetPacketRxGain( void );
//获取数据时的信噪比值,信号和噪声的比值,信噪比越高,说明信号干扰越小。
int8_t SX1276LoRaGetPacketSnr( void );
//获取数据时的无线信号强度
double SX1276LoRaGetPacketRssi( void );
//开始接收
void SX1276LoRaStartRx( void );
//接收数据
void SX1276LoRaGetRxPacket( void *buffer, uint16_t *size );
//发送数据
void SX1276LoRaSetTxPacket( const void *buffer, uint16_t size );
//得到RFLRState状态
uint8_t SX1276LoRaGetRFState( void );
//设置RFLRState状态,RFLRState的值决定了下面的函数处理哪一步的代码
void SX1276LoRaSetRFState( uint8_t state );
//SX1276模块接发收数据的处理函数
uint32_t SX1276LoRaProcess( void );
uint32_t SX1276LoraChannelEmpty( void );
#endif
@@ -0,0 +1,420 @@
/*
* THE FOLLOWING FIRMWARE IS PROVIDED: (1) "AS IS" WITH NO WARRANTY; AND
* (2)TO ENABLE ACCESS TO CODING INFORMATION TO GUIDE AND FACILITATE CUSTOMER.
* CONSEQUENTLY, SEMTECH SHALL NOT BE HELD LIABLE FOR ANY DIRECT, INDIRECT OR
* CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE CONTENT
* OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING INFORMATION
* CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*
* Copyright (C) SEMTECH S.A.
*/
/*!
* \file sx1276-LoRaMisc.c
* \brief SX1276 RF chip high level functions driver
*
* \remark Optional support functions.
* These functions are defined only to easy the change of the
* parameters.
* For a final firmware the radio parameters will be known so
* there is no need to support all possible parameters.
* Removing these functions will greatly reduce the final firmware
* size.
*
* \version 2.0.0
* \date May 6 2013
* \author Gregory Cristian
*
* Last modified by Miguel Luis on Jun 19 2013
*/
/*************************************************
File name: sx1276-LoRaMisc.c
Description: support aiit board configure and register function
History:
1. Date: 2021-04-25
Author: AIIT XUOS Lab
Modification:
1. replace original macro and basic date type with AIIT XUOS Lab's own defination
*************************************************/
#include "platform.h"
#if defined( USE_SX1276_RADIO )
#include "sx1276-Hal.h"
#include "sx1276.h"
#include "sx1276-LoRa.h"
#include "sx1276-LoRaMisc.h"
/*!
* SX1276 definitions
*/
#define XTAL_FREQ 32000000
#define FREQ_STEP 61.03515625
extern tLoRaSettings LoRaSettings;
void SX1276LoRaSetRFFrequency( uint32_t freq )
{
LoRaSettings.RFFrequency = freq;
freq = ( uint32_t )( ( double )freq / ( double )FREQ_STEP );
SX1276LR->RegFrfMsb = ( uint8_t )( ( freq >> 16 ) & 0xFF );
SX1276LR->RegFrfMid = ( uint8_t )( ( freq >> 8 ) & 0xFF );
SX1276LR->RegFrfLsb = ( uint8_t )( freq & 0xFF );
SX1276WriteBuffer( REG_LR_FRFMSB, &SX1276LR->RegFrfMsb, 3 );
}
uint32_t SX1276LoRaGetRFFrequency( void )
{
SX1276ReadBuffer( REG_LR_FRFMSB, &SX1276LR->RegFrfMsb, 3 );
LoRaSettings.RFFrequency = ( ( uint32_t )SX1276LR->RegFrfMsb << 16 ) | ( ( uint32_t )SX1276LR->RegFrfMid << 8 ) | ( ( uint32_t )SX1276LR->RegFrfLsb );
LoRaSettings.RFFrequency = ( uint32_t )( ( double )LoRaSettings.RFFrequency * ( double )FREQ_STEP );
return LoRaSettings.RFFrequency;
}
void SX1276LoRaSetRFPower( int8_t power )
{
SX1276Read( REG_LR_PACONFIG, &SX1276LR->RegPaConfig );
SX1276Read( REG_LR_PADAC, &SX1276LR->RegPaDac );
if( ( SX1276LR->RegPaConfig & RFLR_PACONFIG_PASELECT_PABOOST ) == RFLR_PACONFIG_PASELECT_PABOOST )
{
if( ( SX1276LR->RegPaDac & 0x87 ) == 0x87 )
{
if( power < 5 )
{
power = 5;
}
if( power > 20 )
{
power = 20;
}
SX1276LR->RegPaConfig = ( SX1276LR->RegPaConfig & RFLR_PACONFIG_MAX_POWER_MASK ) | 0x70;
SX1276LR->RegPaConfig = ( SX1276LR->RegPaConfig & RFLR_PACONFIG_OUTPUTPOWER_MASK ) | ( uint8_t )( ( uint16_t )( power - 5 ) & 0x0F );
}
else
{
if( power < 2 )
{
power = 2;
}
if( power > 17 )
{
power = 17;
}
SX1276LR->RegPaConfig = ( SX1276LR->RegPaConfig & RFLR_PACONFIG_MAX_POWER_MASK ) | 0x70;
SX1276LR->RegPaConfig = ( SX1276LR->RegPaConfig & RFLR_PACONFIG_OUTPUTPOWER_MASK ) | ( uint8_t )( ( uint16_t )( power - 2 ) & 0x0F );
}
}
else
{
if( power < -1 )
{
power = -1;
}
if( power > 14 )
{
power = 14;
}
SX1276LR->RegPaConfig = ( SX1276LR->RegPaConfig & RFLR_PACONFIG_MAX_POWER_MASK ) | 0x70;
SX1276LR->RegPaConfig = ( SX1276LR->RegPaConfig & RFLR_PACONFIG_OUTPUTPOWER_MASK ) | ( uint8_t )( ( uint16_t )( power + 1 ) & 0x0F );
}
SX1276Write( REG_LR_PACONFIG, SX1276LR->RegPaConfig );
LoRaSettings.Power = power;
}
int8_t SX1276LoRaGetRFPower( void )
{
SX1276Read( REG_LR_PACONFIG, &SX1276LR->RegPaConfig );
SX1276Read( REG_LR_PADAC, &SX1276LR->RegPaDac );
if( ( SX1276LR->RegPaConfig & RFLR_PACONFIG_PASELECT_PABOOST ) == RFLR_PACONFIG_PASELECT_PABOOST )
{
if( ( SX1276LR->RegPaDac & 0x07 ) == 0x07 )
{
LoRaSettings.Power = 5 + ( SX1276LR->RegPaConfig & ~RFLR_PACONFIG_OUTPUTPOWER_MASK );
}
else
{
LoRaSettings.Power = 2 + ( SX1276LR->RegPaConfig & ~RFLR_PACONFIG_OUTPUTPOWER_MASK );
}
}
else
{
LoRaSettings.Power = -1 + ( SX1276LR->RegPaConfig & ~RFLR_PACONFIG_OUTPUTPOWER_MASK );
}
return LoRaSettings.Power;
}
void SX1276LoRaSetSignalBandwidth( uint8_t bw )
{
SX1276Read( REG_LR_MODEMCONFIG1, &SX1276LR->RegModemConfig1 );
SX1276LR->RegModemConfig1 = ( SX1276LR->RegModemConfig1 & RFLR_MODEMCONFIG1_BW_MASK ) | ( bw << 4 );
SX1276Write( REG_LR_MODEMCONFIG1, SX1276LR->RegModemConfig1 );
LoRaSettings.SignalBw = bw;
}
uint8_t SX1276LoRaGetSignalBandwidth( void )
{
SX1276Read( REG_LR_MODEMCONFIG1, &SX1276LR->RegModemConfig1 );
LoRaSettings.SignalBw = ( SX1276LR->RegModemConfig1 & ~RFLR_MODEMCONFIG1_BW_MASK ) >> 4;
return LoRaSettings.SignalBw;
}
void SX1276LoRaSetSpreadingFactor( uint8_t factor )
{
if( factor > 12 )
{
factor = 12;
}
else if( factor < 6 )
{
factor = 6;
}
if( factor == 6 )
{
SX1276LoRaSetNbTrigPeaks( 5 );
}
else
{
SX1276LoRaSetNbTrigPeaks( 3 );
}
SX1276Read( REG_LR_MODEMCONFIG2, &SX1276LR->RegModemConfig2 );
SX1276LR->RegModemConfig2 = ( SX1276LR->RegModemConfig2 & RFLR_MODEMCONFIG2_SF_MASK ) | ( factor << 4 );
SX1276Write( REG_LR_MODEMCONFIG2, SX1276LR->RegModemConfig2 );
LoRaSettings.SpreadingFactor = factor;
}
uint8_t SX1276LoRaGetSpreadingFactor( void )
{
SX1276Read( REG_LR_MODEMCONFIG2, &SX1276LR->RegModemConfig2 );
LoRaSettings.SpreadingFactor = ( SX1276LR->RegModemConfig2 & ~RFLR_MODEMCONFIG2_SF_MASK ) >> 4;
return LoRaSettings.SpreadingFactor;
}
void SX1276LoRaSetErrorCoding( uint8_t value )
{
SX1276Read( REG_LR_MODEMCONFIG1, &SX1276LR->RegModemConfig1 );
SX1276LR->RegModemConfig1 = ( SX1276LR->RegModemConfig1 & RFLR_MODEMCONFIG1_CODINGRATE_MASK ) | ( value << 1 );
SX1276Write( REG_LR_MODEMCONFIG1, SX1276LR->RegModemConfig1 );
LoRaSettings.ErrorCoding = value;
}
uint8_t SX1276LoRaGetErrorCoding( void )
{
SX1276Read( REG_LR_MODEMCONFIG1, &SX1276LR->RegModemConfig1 );
LoRaSettings.ErrorCoding = ( SX1276LR->RegModemConfig1 & ~RFLR_MODEMCONFIG1_CODINGRATE_MASK ) >> 1;
return LoRaSettings.ErrorCoding;
}
void SX1276LoRaSetPacketCrcOn( bool enable )
{
SX1276Read( REG_LR_MODEMCONFIG2, &SX1276LR->RegModemConfig2 );
SX1276LR->RegModemConfig2 = ( SX1276LR->RegModemConfig2 & RFLR_MODEMCONFIG2_RXPAYLOADCRC_MASK ) | ( enable << 2 );
SX1276Write( REG_LR_MODEMCONFIG2, SX1276LR->RegModemConfig2 );
LoRaSettings.CrcOn = enable;
}
void SX1276LoRaSetPreambleLength( uint16_t value )
{
SX1276ReadBuffer( REG_LR_PREAMBLEMSB, &SX1276LR->RegPreambleMsb, 2 );
SX1276LR->RegPreambleMsb = ( value >> 8 ) & 0x00FF;
SX1276LR->RegPreambleLsb = value & 0xFF;
SX1276WriteBuffer( REG_LR_PREAMBLEMSB, &SX1276LR->RegPreambleMsb, 2 );
}
uint16_t SX1276LoRaGetPreambleLength( void )
{
SX1276ReadBuffer( REG_LR_PREAMBLEMSB, &SX1276LR->RegPreambleMsb, 2 );
return ( ( SX1276LR->RegPreambleMsb & 0x00FF ) << 8 ) | SX1276LR->RegPreambleLsb;
}
bool SX1276LoRaGetPacketCrcOn( void )
{
SX1276Read( REG_LR_MODEMCONFIG2, &SX1276LR->RegModemConfig2 );
LoRaSettings.CrcOn = ( SX1276LR->RegModemConfig2 & RFLR_MODEMCONFIG2_RXPAYLOADCRC_ON ) >> 1;
return LoRaSettings.CrcOn;
}
void SX1276LoRaSetImplicitHeaderOn( bool enable )
{
SX1276Read( REG_LR_MODEMCONFIG1, &SX1276LR->RegModemConfig1 );
SX1276LR->RegModemConfig1 = ( SX1276LR->RegModemConfig1 & RFLR_MODEMCONFIG1_IMPLICITHEADER_MASK ) | ( enable );
SX1276Write( REG_LR_MODEMCONFIG1, SX1276LR->RegModemConfig1 );
LoRaSettings.ImplicitHeaderOn = enable;
}
bool SX1276LoRaGetImplicitHeaderOn( void )
{
SX1276Read( REG_LR_MODEMCONFIG1, &SX1276LR->RegModemConfig1 );
LoRaSettings.ImplicitHeaderOn = ( SX1276LR->RegModemConfig1 & RFLR_MODEMCONFIG1_IMPLICITHEADER_ON );
return LoRaSettings.ImplicitHeaderOn;
}
void SX1276LoRaSetRxSingleOn( bool enable )
{
LoRaSettings.RxSingleOn = enable;
}
bool SX1276LoRaGetRxSingleOn( void )
{
return LoRaSettings.RxSingleOn;
}
void SX1276LoRaSetFreqHopOn( bool enable )
{
LoRaSettings.FreqHopOn = enable;
}
bool SX1276LoRaGetFreqHopOn( void )
{
return LoRaSettings.FreqHopOn;
}
void SX1276LoRaSetHopPeriod( uint8_t value )
{
SX1276LR->RegHopPeriod = value;
SX1276Write( REG_LR_HOPPERIOD, SX1276LR->RegHopPeriod );
LoRaSettings.HopPeriod = value;
}
uint8_t SX1276LoRaGetHopPeriod( void )
{
SX1276Read( REG_LR_HOPPERIOD, &SX1276LR->RegHopPeriod );
LoRaSettings.HopPeriod = SX1276LR->RegHopPeriod;
return LoRaSettings.HopPeriod;
}
void SX1276LoRaSetTxPacketTimeout( uint32_t value )
{
LoRaSettings.TxPacketTimeout = value;
}
uint32_t SX1276LoRaGetTxPacketTimeout( void )
{
return LoRaSettings.TxPacketTimeout;
}
void SX1276LoRaSetRxPacketTimeout( uint32_t value )
{
LoRaSettings.RxPacketTimeout = value;
}
uint32_t SX1276LoRaGetRxPacketTimeout( void )
{
return LoRaSettings.RxPacketTimeout;
}
void SX1276LoRaSetPayloadLength( uint8_t value )
{
SX1276LR->RegPayloadLength = value;
SX1276Write( REG_LR_PAYLOADLENGTH, SX1276LR->RegPayloadLength );
LoRaSettings.PayloadLength = value;
}
uint8_t SX1276LoRaGetPayloadLength( void )
{
SX1276Read( REG_LR_PAYLOADLENGTH, &SX1276LR->RegPayloadLength );
LoRaSettings.PayloadLength = SX1276LR->RegPayloadLength;
return LoRaSettings.PayloadLength;
}
void SX1276LoRaSetPa20dBm( bool enale )
{
SX1276Read( REG_LR_PADAC, &SX1276LR->RegPaDac );
SX1276Read( REG_LR_PACONFIG, &SX1276LR->RegPaConfig );
if( ( SX1276LR->RegPaConfig & RFLR_PACONFIG_PASELECT_PABOOST ) == RFLR_PACONFIG_PASELECT_PABOOST )
{
if( enale == true )
{
SX1276LR->RegPaDac = 0x87;
}
}
else
{
SX1276LR->RegPaDac = 0x84;
}
SX1276Write( REG_LR_PADAC, SX1276LR->RegPaDac );
}
bool SX1276LoRaGetPa20dBm( void )
{
SX1276Read( REG_LR_PADAC, &SX1276LR->RegPaDac );
return ( ( SX1276LR->RegPaDac & 0x07 ) == 0x07 ) ? true : false;
}
void SX1276LoRaSetPAOutput( uint8_t outputPin )
{
SX1276Read( REG_LR_PACONFIG, &SX1276LR->RegPaConfig );
SX1276LR->RegPaConfig = (SX1276LR->RegPaConfig & RFLR_PACONFIG_PASELECT_MASK ) | outputPin;
SX1276Write( REG_LR_PACONFIG, SX1276LR->RegPaConfig );
}
uint8_t SX1276LoRaGetPAOutput( void )
{
SX1276Read( REG_LR_PACONFIG, &SX1276LR->RegPaConfig );
return SX1276LR->RegPaConfig & ~RFLR_PACONFIG_PASELECT_MASK;
}
void SX1276LoRaSetPaRamp( uint8_t value )
{
SX1276Read( REG_LR_PARAMP, &SX1276LR->RegPaRamp );
SX1276LR->RegPaRamp = ( SX1276LR->RegPaRamp & RFLR_PARAMP_MASK ) | ( value & ~RFLR_PARAMP_MASK );
SX1276Write( REG_LR_PARAMP, SX1276LR->RegPaRamp );
}
uint8_t SX1276LoRaGetPaRamp( void )
{
SX1276Read( REG_LR_PARAMP, &SX1276LR->RegPaRamp );
return SX1276LR->RegPaRamp & ~RFLR_PARAMP_MASK;
}
void SX1276LoRaSetSymbTimeout( uint16_t value )
{
SX1276ReadBuffer( REG_LR_MODEMCONFIG2, &SX1276LR->RegModemConfig2, 2 );
SX1276LR->RegModemConfig2 = ( SX1276LR->RegModemConfig2 & RFLR_MODEMCONFIG2_SYMBTIMEOUTMSB_MASK ) | ( ( value >> 8 ) & ~RFLR_MODEMCONFIG2_SYMBTIMEOUTMSB_MASK );
SX1276LR->RegSymbTimeoutLsb = value & 0xFF;
SX1276WriteBuffer( REG_LR_MODEMCONFIG2, &SX1276LR->RegModemConfig2, 2 );
}
uint16_t SX1276LoRaGetSymbTimeout( void )
{
SX1276ReadBuffer( REG_LR_MODEMCONFIG2, &SX1276LR->RegModemConfig2, 2 );
return ( ( SX1276LR->RegModemConfig2 & ~RFLR_MODEMCONFIG2_SYMBTIMEOUTMSB_MASK ) << 8 ) | SX1276LR->RegSymbTimeoutLsb;
}
void SX1276LoRaSetLowDatarateOptimize( bool enable )
{
SX1276Read( REG_LR_MODEMCONFIG3, &SX1276LR->RegModemConfig3 );
SX1276LR->RegModemConfig3 = ( SX1276LR->RegModemConfig3 & RFLR_MODEMCONFIG3_LOWDATARATEOPTIMIZE_MASK ) | ( enable << 3 );
SX1276Write( REG_LR_MODEMCONFIG3, SX1276LR->RegModemConfig3 );
}
bool SX1276LoRaGetLowDatarateOptimize( void )
{
SX1276Read( REG_LR_MODEMCONFIG3, &SX1276LR->RegModemConfig3 );
return ( ( SX1276LR->RegModemConfig3 & RFLR_MODEMCONFIG3_LOWDATARATEOPTIMIZE_ON ) >> 3 );
}
void SX1276LoRaSetNbTrigPeaks( uint8_t value )
{
SX1276Read( 0x31, &SX1276LR->RegTestReserved31 );
SX1276LR->RegTestReserved31 = ( SX1276LR->RegTestReserved31 & 0xF8 ) | value;//数据包长度最高有效位 0x31 bit2 1 0
SX1276Write( 0x31, SX1276LR->RegTestReserved31 );
}
uint8_t SX1276LoRaGetNbTrigPeaks( void )
{
SX1276Read( 0x31, &SX1276LR->RegTestReserved31 );
return ( SX1276LR->RegTestReserved31 & 0x07 );
}
#endif // USE_SX1276_RADIO
@@ -0,0 +1,324 @@
/*
* THE FOLLOWING FIRMWARE IS PROVIDED: (1) "AS IS" WITH NO WARRANTY; AND
* (2)TO ENABLE ACCESS TO CODING INFORMATION TO GUIDE AND FACILITATE CUSTOMER.
* CONSEQUENTLY, SEMTECH SHALL NOT BE HELD LIABLE FOR ANY DIRECT, INDIRECT OR
* CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE CONTENT
* OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING INFORMATION
* CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*
* Copyright (C) SEMTECH S.A.
*/
/*!
* \file sx1276-LoRaMisc.h
* \brief SX1276 RF chip high level functions driver
*
* \remark Optional support functions.
* These functions are defined only to easy the change of the
* parameters.
* For a final firmware the radio parameters will be known so
* there is no need to support all possible parameters.
* Removing these functions will greatly reduce the final firmware
* size.
*
* \version 2.0.0
* \date May 6 2013
* \author Gregory Cristian
*
* Last modified by Miguel Luis on Jun 19 2013
*/
/*************************************************
File name: sx1276-LoRaMisc.h
Description: support aiit board configure and register function
History:
1. Date: 2021-04-25
Author: AIIT XUOS Lab
Modification:
1. replace original macro and basic date type with AIIT XUOS Lab's own defination
*************************************************/
#ifndef __SX1276_LORA_MISC_H__
#define __SX1276_LORA_MISC_H__
#include "stdint.h"
#include "stdbool.h"
/*!
* \brief Writes the new RF frequency value
*
* \param [IN] freq New RF frequency value in [Hz]
*/
void SX1276LoRaSetRFFrequency( uint32_t freq );
/*!
* \brief Reads the current RF frequency value
*
* \retval freq Current RF frequency value in [Hz]
*/
uint32_t SX1276LoRaGetRFFrequency( void );
/*!
* \brief Writes the new RF output power value
*
* \param [IN] power New output power value in [dBm]
*/
void SX1276LoRaSetRFPower( int8_t power );
/*!
* \brief Reads the current RF output power value
*
* \retval power Current output power value in [dBm]
*/
int8_t SX1276LoRaGetRFPower( void );
/*!
* \brief Writes the new Signal Bandwidth value
*
* \remark This function sets the IF frequency according to the datasheet
*
* \param [IN] factor New Signal Bandwidth value [0: 125 kHz, 1: 250 kHz, 2: 500 kHz]
*/
void SX1276LoRaSetSignalBandwidth( uint8_t bw );
/*!
* \brief Reads the current Signal Bandwidth value
*
* \retval factor Current Signal Bandwidth value [0: 125 kHz, 1: 250 kHz, 2: 500 kHz]
*/
uint8_t SX1276LoRaGetSignalBandwidth( void );
/*!
* \brief Writes the new Spreading Factor value
*
* \param [IN] factor New Spreading Factor value [7, 8, 9, 10, 11, 12]
*/
void SX1276LoRaSetSpreadingFactor( uint8_t factor );
/*!
* \brief Reads the current Spreading Factor value
*
* \retval factor Current Spreading Factor value [7, 8, 9, 10, 11, 12]
*/
uint8_t SX1276LoRaGetSpreadingFactor( void );
/*!
* \brief Writes the new Error Coding value
*
* \param [IN] value New Error Coding value [1: 4/5, 2: 4/6, 3: 4/7, 4: 4/8]
*/
void SX1276LoRaSetErrorCoding( uint8_t value );
/*!
* \brief Reads the current Error Coding value
*
* \retval value Current Error Coding value [1: 4/5, 2: 4/6, 3: 4/7, 4: 4/8]
*/
uint8_t SX1276LoRaGetErrorCoding( void );
/*!
* \brief Enables/Disables the packet CRC generation
*
* \param [IN] enaable [true, false]
*/
void SX1276LoRaSetPacketCrcOn( bool enable );
/*!
* \brief Reads the current packet CRC generation status
*
* \retval enable [true, false]
*/
bool SX1276LoRaGetPacketCrcOn( void );
/*!
* \brief Enables/Disables the Implicit Header mode in LoRa
*
* \param [IN] enable [true, false]
*/
void SX1276LoRaSetImplicitHeaderOn( bool enable );
/*!
* \brief Check if implicit header mode in LoRa in enabled or disabled
*
* \retval enable [true, false]
*/
bool SX1276LoRaGetImplicitHeaderOn( void );
/*!
* \brief Enables/Disables Rx single instead of Rx continuous
*
* \param [IN] enable [true, false]
*/
void SX1276LoRaSetRxSingleOn( bool enable );
/*!
* \brief Check if LoRa is in Rx Single mode
*
* \retval enable [true, false]
*/
bool SX1276LoRaGetRxSingleOn( void );
/*!
* \brief Enables/Disables the frequency hopping
*
* \param [IN] enable [true, false]
*/
void SX1276LoRaSetFreqHopOn( bool enable );
/*!
* \brief Get the frequency hopping status
*
* \param [IN] enable [true, false]
*/
bool SX1276LoRaGetFreqHopOn( void );
/*!
* \brief Set symbol period between frequency hops
*
* \param [IN] value
*/
void SX1276LoRaSetHopPeriod( uint8_t value );
/*!
* \brief Get symbol period between frequency hops
*
* \retval value symbol period between frequency hops
*/
uint8_t SX1276LoRaGetHopPeriod( void );
/*!
* \brief Set timeout Tx packet (based on MCU timer, timeout between Tx Mode entry Tx Done IRQ)
*
* \param [IN] value timeout (ms)
*/
void SX1276LoRaSetTxPacketTimeout( uint32_t value );
/*!
* \brief Get timeout between Tx packet (based on MCU timer, timeout between Tx Mode entry Tx Done IRQ)
*
* \retval value timeout (ms)
*/
uint32_t SX1276LoRaGetTxPacketTimeout( void );
/*!
* \brief Set timeout Rx packet (based on MCU timer, timeout between Rx Mode entry and Rx Done IRQ)
*
* \param [IN] value timeout (ms)
*/
void SX1276LoRaSetRxPacketTimeout( uint32_t value );
/*!
* \brief Get timeout Rx packet (based on MCU timer, timeout between Rx Mode entry and Rx Done IRQ)
*
* \retval value timeout (ms)
*/
uint32_t SX1276LoRaGetRxPacketTimeout( void );
/*!
* \brief Set payload length
*
* \param [IN] value payload length
*/
void SX1276LoRaSetPayloadLength( uint8_t value );
/*!
* \brief Get payload length
*
* \retval value payload length
*/
uint8_t SX1276LoRaGetPayloadLength( void );
/*!
* \brief Enables/Disables the 20 dBm PA
*
* \param [IN] enable [true, false]
*/
void SX1276LoRaSetPa20dBm( bool enale );
/*!
* \brief Gets the current 20 dBm PA status
*
* \retval enable [true, false]
*/
bool SX1276LoRaGetPa20dBm( void );
/*!
* \brief Set the RF Output pin
*
* \param [IN] RF_PACONFIG_PASELECT_PABOOST or RF_PACONFIG_PASELECT_RFO
*/
void SX1276LoRaSetPAOutput( uint8_t outputPin );
/*!
* \brief Gets the used RF Ouptut pin
*
* \retval RF_PACONFIG_PASELECT_PABOOST or RF_PACONFIG_PASELECT_RFO
*/
uint8_t SX1276LoRaGetPAOutput( void );
/*!
* \brief Writes the new PA rise/fall time of ramp up/down value
*
* \param [IN] value New PaRamp value
*/
void SX1276LoRaSetPaRamp( uint8_t value );
/*!
* \brief Reads the current PA rise/fall time of ramp up/down value
*
* \retval freq Current PaRamp value
*/
uint8_t SX1276LoRaGetPaRamp( void );
/*!
* \brief Set Symbol Timeout based on symbol length
*
* \param [IN] value number of symbol
*/
void SX1276LoRaSetSymbTimeout( uint16_t value );
/*!
* \brief Get Symbol Timeout based on symbol length
*
* \retval value number of symbol
*/
uint16_t SX1276LoRaGetSymbTimeout( void );
/*!
* \brief Configure the device to optimize low datarate transfers
*
* \param [IN] enable Enables/Disables the low datarate optimization
*/
void SX1276LoRaSetLowDatarateOptimize( bool enable );
/*!
* \brief Get the status of optimize low datarate transfers
*
* \retval LowDatarateOptimize enable or disable
*/
bool SX1276LoRaGetLowDatarateOptimize( void );
/*!
* \brief Get the preamble length
*
* \retval value preamble length
*/
uint16_t SX1276LoRaGetPreambleLength( void );
/*!
* \brief Set the preamble length
*
* \param [IN] value preamble length
*/
void SX1276LoRaSetPreambleLength( uint16_t value );
/*!
* \brief Set the number or rolling preamble symbol needed for detection
*
* \param [IN] value number of preamble symbol
*/
void SX1276LoRaSetNbTrigPeaks( uint8_t value );
/*!
* \brief Get the number or rolling preamble symbol needed for detection
*
* \retval value number of preamble symbol
*/
uint8_t SX1276LoRaGetNbTrigPeaks( void );
#endif
@@ -0,0 +1,282 @@
/*
* THE FOLLOWING FIRMWARE IS PROVIDED: (1) "AS IS" WITH NO WARRANTY; AND
* (2)TO ENABLE ACCESS TO CODING INFORMATION TO GUIDE AND FACILITATE CUSTOMER.
* CONSEQUENTLY, SEMTECH SHALL NOT BE HELD LIABLE FOR ANY DIRECT, INDIRECT OR
* CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE CONTENT
* OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING INFORMATION
* CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*
* Copyright (C) SEMTECH S.A.
*/
/*!
* \file sx1276.c
* \brief SX1276 RF chip high level functions driver
*
* \remark Optional support functions.
* These functions are defined only to easy the change of the
* parameters.
* For a final firmware the radio parameters will be known so
* there is no need to support all possible parameters.
* Removing these functions will greatly reduce the final firmware
* size.
*
* \version 2.0.0
* \date May 6 2013
* \author Gregory Cristian
*
* Last modified by Miguel Luis on Jun 19 2013
*/
/*************************************************
File name: sx1276.c
Description: support aiit board configure and register function
History:
1. Date: 2021-04-25
Author: AIIT XUOS Lab
Modification:
1. replace original macro and basic date type with AIIT XUOS Lab's own defination
*************************************************/
#include "platform.h"
#include "radio.h"
#if defined(USE_SX1276_RADIO)
#include "sx1276.h"
#include "sx1276-Hal.h"
#include "sx1276-Fsk.h"
#include "sx1276-LoRa.h"
uint8_t SX1276Regs[0x70];
static bool LoRaOn = true;
static bool LoRaOnState = false;
void SX1276Reset(void)
{
uint32_t startTick;
SX1276SetReset(RADIO_RESET_ON);
DDL_DelayMS(1);
SX1276SetReset(RADIO_RESET_OFF);
DDL_DelayMS(6);
}
void SX1276_SetLoRaOn(bool enable)
{
if(LoRaOnState == enable) {
return;
}
LoRaOnState = enable;
LoRaOn = enable;
if(LoRaOn == true) {
SX1276LoRaSetOpMode(RFLR_OPMODE_SLEEP);
SX1276LR->RegOpMode = (SX1276LR->RegOpMode & RFLR_OPMODE_LONGRANGEMODE_MASK) | RFLR_OPMODE_LONGRANGEMODE_ON;
SX1276Write(REG_LR_OPMODE, SX1276LR->RegOpMode);
SX1276LoRaSetOpMode(RFLR_OPMODE_STANDBY);
// RxDone RxTimeout FhssChangeChannel CadDone
SX1276LR->RegDioMapping1 = RFLR_DIOMAPPING1_DIO0_00 | RFLR_DIOMAPPING1_DIO1_00 | RFLR_DIOMAPPING1_DIO2_00 | RFLR_DIOMAPPING1_DIO3_00;
// CadDetected ModeReady
SX1276LR->RegDioMapping2 = RFLR_DIOMAPPING2_DIO4_00 | RFLR_DIOMAPPING2_DIO5_00;
SX1276WriteBuffer(REG_LR_DIOMAPPING1, &SX1276LR->RegDioMapping1, 2);
SX1276ReadBuffer(REG_LR_OPMODE, SX1276Regs + 1, 0x70 - 1);
} else {
SX1276LoRaSetOpMode(RFLR_OPMODE_SLEEP);
SX1276LR->RegOpMode = (SX1276LR->RegOpMode & RFLR_OPMODE_LONGRANGEMODE_MASK) | RFLR_OPMODE_LONGRANGEMODE_OFF;
SX1276Write(REG_LR_OPMODE, SX1276LR->RegOpMode);
SX1276LoRaSetOpMode(RFLR_OPMODE_STANDBY);
SX1276ReadBuffer(REG_OPMODE, SX1276Regs + 1, 0x70 - 1);
}
}
bool SX1276_GetLoRaOn(void)
{
return LoRaOn;
}
void SX1276SetOpMode(uint8_t opMode)
{
if(LoRaOn == false) {
SX1276FskSetOpMode(opMode);
} else {
SX1276LoRaSetOpMode(opMode);
}
}
uint8_t SX1276_GetOpMode(void)
{
if(LoRaOn == false) {
return SX1276FskGetOpMode();
} else {
return SX1276LoRaGetOpMode();
}
}
double SX1276ReadRssi(void)
{
if(LoRaOn == false) {
return SX1276FskReadRssi();
} else {
return SX1276LoRaReadRssi();
}
}
uint8_t SX1276_ReadRxGain(void)
{
if(LoRaOn == false) {
return SX1276FskReadRxGain();
} else {
return SX1276LoRaReadRxGain();
}
}
uint8_t SX1276_GetPacketRxGain(void)
{
if(LoRaOn == false) {
return SX1276FskGetPacketRxGain();
} else {
return SX1276LoRaGetPacketRxGain();
}
}
int8_t SX1276_GetPacketSnr(void)
{
if(LoRaOn == false) {
while(1) {
// Useless in FSK mode
// Block program here
}
} else {
return SX1276LoRaGetPacketSnr();
}
}
double SX1276_GetPacketRssi(void)
{
if(LoRaOn == false) {
return SX1276FskGetPacketRssi();
} else {
return SX1276LoRaGetPacketRssi();
}
}
uint32_t SX1276GetPacketAfc(void)
{
if(LoRaOn == false) {
return SX1276FskGetPacketAfc();
} else {
while(1) {
// Useless in LoRa mode
// Block program here
}
}
}
void SX1276StartRx(void)
{
if(LoRaOn == false) {
SX1276FskSetRFState(RF_STATE_RX_INIT);
} else {
SX1276LoRaSetRFState(RFLR_STATE_RX_INIT);
}
}
void SX1276GetRxPacket(void *buffer, uint16_t *size)
{
if(LoRaOn == false) {
SX1276FskGetRxPacket(buffer, size);
} else {
SX1276LoRaGetRxPacket(buffer, size);
}
}
void SX1276SetTxPacket(const void *buffer, uint16_t size)
{
if(LoRaOn == false) {
SX1276FskSetTxPacket(buffer, size);
} else {
SX1276LoRaSetTxPacket(buffer, size);
}
}
uint8_t SX1276GetRFState(void)
{
if(LoRaOn == false) {
return SX1276FskGetRFState();
} else {
return SX1276LoRaGetRFState();
}
}
void SX1276SetRFState(uint8_t state)
{
if(LoRaOn == false) {
SX1276FskSetRFState(state);
} else {
SX1276LoRaSetRFState(state);
}
}
uint32_t SX1276Process(void)
{
if(LoRaOn == false) {
return SX1276FskProcess();
} else {
return SX1276LoRaProcess();
}
}
uint32_t SX1276ChannelEmpty(void)
{
if(LoRaOn == false) {
return true;
} else {
SX1276LoraChannelEmpty();
}
}
void SX1276Init(void)
{
uint8_t TempReg;
SX1276 = (tSX1276 *)SX1276Regs;
SX1276LR = (tSX1276LR *)SX1276Regs;
SX1276InitIo();
SX1276Reset();
SX1276Read(0x06, &TempReg);
if(TempReg != 0x6C) {
KPrintf("Hard SPI Err!\r\n");
}
SX1276Read(0x42, &TempReg);
if(TempReg != 0x12) {
KPrintf("Hard SPI Err! version 0x%x\r\n", TempReg);
}
#if (LORA == 0)
LoRaOn = false;
SX1276_SetLoRaOn(LoRaOn);
SX1276FskInit();
#else
LoRaOn = true;
SX1276_SetLoRaOn(LoRaOn);
SX1276LoRaInit();
#endif
}
#endif
@@ -0,0 +1,93 @@
/*
* THE FOLLOWING FIRMWARE IS PROVIDED: (1) "AS IS" WITH NO WARRANTY; AND
* (2)TO ENABLE ACCESS TO CODING INFORMATION TO GUIDE AND FACILITATE CUSTOMER.
* CONSEQUENTLY, SEMTECH SHALL NOT BE HELD LIABLE FOR ANY DIRECT, INDIRECT OR
* CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE CONTENT
* OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING INFORMATION
* CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*
* Copyright (C) SEMTECH S.A.
*/
/*!
* \file sx1276.h
* \brief SX1276 RF chip high level functions driver
*
* \remark Optional support functions.
* These functions are defined only to easy the change of the
* parameters.
* For a final firmware the radio parameters will be known so
* there is no need to support all possible parameters.
* Removing these functions will greatly reduce the final firmware
* size.
*
* \version 2.0.0
* \date May 6 2013
* \author Gregory Cristian
*
* Last modified by Miguel Luis on Jun 19 2013
*/
/*************************************************
File name: sx1276.h
Description: support aiit board configure and register function
History:
1. Date: 2021-04-25
Author: AIIT XUOS Lab
Modification:
1. replace original macro and basic date type with AIIT XUOS Lab's own defination
*************************************************/
#ifndef __SX1276_H__
#define __SX1276_H__
#include <stdint.h>
#include <stdbool.h>
extern uint8_t SX1276Regs[0x70]; //SX1276寄存器数组
void SX1276Init( void ); //初始化SX1276
void SX1276Reset( void ); //重置SX1276
/*以下函数都没有被使用到,因为在sx1276-LoRa.h里面又定义了一系列与下面作用相同的函数*/
void SX1276_SetLoRaOn( bool enable ); //启用LoRa调制解调器或FSK调制解调器
bool SX1276_GetLoRaOn( void ); //获取LoRa调制解调器状态
void SX1276SetOpMode( uint8_t opMode ); //设置SX1276操作模式
uint8_t SX1276_GetOpMode( void ); //获取SX1276操作模式
uint8_t SX1276_ReadRxGain( void ); //读取当前Rx增益设置
double SX1276ReadRssi( void ); //读取无线信号强度
uint8_t SX1276_GetPacketRxGain( void ); //获取数据时的增益值
int8_t SX1276_GetPacketSnr( void ); //获取数据时的信噪比值,信号和噪声的比值,信噪比越高,说明信号干扰越小。
double SX1276_GetPacketRssi( void ); //获取数据是的无线信号强度
/*!
* \brief Gets the AFC value measured while receiving the packet
*
* \retval afcValue Current AFC value in [Hz]
*/
uint32_t SX1276GetPacketAfc( void ); //此函数不知道作用
void SX1276StartRx( void ); //开始接收
void SX1276GetRxPacket( void *buffer, uint16_t *size ); //得到接收的数据
void SX1276SetTxPacket( const void *buffer, uint16_t size ); //发送数据
uint8_t SX1276GetRFState( void ); //得到RFLRState状态
void SX1276SetRFState( uint8_t state ); //设置RFLRState状态,RFLRState的值决定了下面的函数处理哪一步的代码
uint32_t SX1276Process( void ); //SX1276模块接发收数据的处理函数
uint32_t SX1276ChannelEmpty( void );
#endif
@@ -104,12 +104,22 @@ struct SerialHardwareDevice serial_device_3;
void Uart3RxIrqHandler(void)
{
x_base lock = 0;
lock = DISABLE_INTERRUPT();
SerialSetIsr(&serial_device_3, SERIAL_EVENT_RX_IND);
ENABLE_INTERRUPT(lock);
}
void Uart3RxErrIrqHandler(void)
{
x_base lock = 0;
lock = DISABLE_INTERRUPT();
UartRxErrIsr(&serial_bus_3, &serial_driver_3, &serial_device_3);
ENABLE_INTERRUPT(lock);
}
#endif
@@ -120,12 +130,22 @@ struct SerialHardwareDevice serial_device_6;
void Uart6RxIrqHandler(void)
{
x_base lock = 0;
lock = DISABLE_INTERRUPT();
SerialSetIsr(&serial_device_6, SERIAL_EVENT_RX_IND);
ENABLE_INTERRUPT(lock);
}
void Uart6RxErrIrqHandler(void)
{
x_base lock = 0;
lock = DISABLE_INTERRUPT();
UartRxErrIsr(&serial_bus_6, &serial_driver_6, &serial_device_6);
ENABLE_INTERRUPT(lock);
}
#endif
@@ -0,0 +1,25 @@
config BSP_USING_HC32_USBH
bool "Using usb host by HC32 library"
default y
if BSP_USING_HC32_USBH
config USB_BUS_NAME
string "usb bus name"
default "usb"
config USB_DRIVER_NAME
string "usb bus driver name"
default "usb_drv"
config USB_DEVICE_NAME
string "usb bus device name"
default "usb_dev"
config MOUNT_USB_FS
bool "mount usb file system : if y then not support sdcard-mount-fs"
default y
select MOUNT_USB
if MOUNT_USB_FS
config MOUNT_USB_FS_TYPE
int "choose file system type : FATFS(0)"
default 0
endif
endif
@@ -0,0 +1,5 @@
SRC_DIR := hc32_usb_driver
SRC_FILES := connect_usb.c
include $(KERNEL_ROOT)/compiler.mk
@@ -0,0 +1,235 @@
/*
* Copyright (c) 2020 AIIT XUOS Lab
* XiUOS is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
/**
* @file connect_usb.c
* @brief support hc32f4a0-board usb function and register to bus framework
* @version 2.0
* @author AIIT XUOS Lab
* @date 2022-11-07
*/
/*************************************************
File name: connect_usb.c
Description: support hc32f4a0-board usb function and register to bus framework
Others:
History:
1. Date: 2022-11-07
Author: AIIT XUOS Lab
Modification:
1. support hc32f4a0-board usb configure, write and read
2. support hc32f4a0-board usb bus device and driver register
*************************************************/
#include <connect_usb.h>
usb_core_instance usb_app_instance;
USBH_HOST usb_app_host;
static void UsbHostTask(void *parameter);
#if defined(FS_VFS)
void UsbMountFileSystem()
{
if (MountFilesystem(USB_BUS_NAME, USB_DEVICE_NAME, USB_DRIVER_NAME, FSTYPE_FATFS, UDISK_MOUNTPOINT) == 0)
KPrintf("Mount FAT on Udisk successful.\n");
else
KPrintf("Mount FAT on Udisk failed.\n");
}
void UsbUnmountFileSystem()
{
UnmountFileSystem(UDISK_MOUNTPOINT);
}
#ifdef MOUNT_USB
int MountUsb(void)
{
int32 usb_host_task = 0;
usb_host_task = KTaskCreate("usbh", UsbHostTask, NONE,
USB_HOST_STACK_SIZE, 8);
if(usb_host_task < 0) {
KPrintf("usb_host_task create failed ...%s %d.\n", __FUNCTION__, __LINE__);
return ERROR;
}
StartupKTask(usb_host_task);
return 0;
}
#endif
#endif
static uint32 UsbHostOpen(void *dev)
{
return EOK;
}
static uint32 UsbHostClose(void *dev)
{
return EOK;
}
static uint32 UsbHostRead(void *dev, struct BusBlockReadParam *read_param)
{
USB_HOST_MSC_STATUS status = USB_HOST_MSC_OK;
if (host_driver_ifdevconnected(&usb_app_instance) != 0UL) {
do {
status = usb_host_msc_Read10(&usb_app_instance, (uint8 *)read_param->buffer, read_param->pos, USB_SINGLE_BLOCK_SIZE * (uint32_t)read_param->size);
usb_host_msc_botxferprocess(&usb_app_instance, &usb_app_host);
if (host_driver_ifdevconnected(&usb_app_instance) == 0UL) {
return 0;
}
} while (USB_HOST_MSC_BUSY == status);
}
if (USB_HOST_MSC_OK == status) {
return read_param->size;
}
return 0;
}
static uint32 UsbHostWrite(void *dev, struct BusBlockWriteParam *write_param)
{
USB_HOST_MSC_STATUS status = USB_HOST_MSC_OK;
if (host_driver_ifdevconnected(&usb_app_instance) != 0UL) {
do {
status = usb_host_msc_Write10(&usb_app_instance, (uint8 *)write_param->buffer, write_param->pos, USB_SINGLE_BLOCK_SIZE * (uint32_t)write_param->size);
usb_host_msc_botxferprocess(&usb_app_instance, &usb_app_host);
if (host_driver_ifdevconnected(&usb_app_instance) == 0UL) {
return 0;
}
} while (USB_HOST_MSC_BUSY == status);
}
if (USB_HOST_MSC_OK == status) {
return write_param->size;
}
return 0;
}
static int UsbControl(struct HardwareDev *dev, struct HalDevBlockParam *block_param)
{
NULL_PARAM_CHECK(dev);
if (OPER_BLK_GETGEOME == block_param->cmd) {
block_param->dev_block.size_perbank = USB_SINGLE_BLOCK_SIZE;
block_param->dev_block.block_size = USB_SINGLE_BLOCK_SIZE;
block_param->dev_block.bank_num = USB_HOST_MSC_Param.MSC_Capacity;
}
return EOK;
}
/*manage the usb device operations*/
static const struct UsbDevDone dev_done =
{
.open = UsbHostOpen,
.close = UsbHostClose,
.write = UsbHostWrite,
.read = UsbHostRead,
};
static void UsbHostTask(void *parameter)
{
usb_host_init(&usb_app_instance, &usb_app_host, &USBH_MSC_cb, &USR_cb);
while (1) {
usb_host_mainprocess(&usb_app_instance, &usb_app_host);
}
}
/*Init usb host bus、driver*/
static int BoardUsbBusInit(struct UsbBus *usb_bus, struct UsbDriver *usb_driver)
{
x_err_t ret = EOK;
/*Init the usb bus */
ret = UsbBusInit(usb_bus, USB_BUS_NAME);
if (EOK != ret) {
KPrintf("board_usb_init UsbBusInit error %d\n", ret);
return ERROR;
}
/*Init the usb driver*/
ret = UsbDriverInit(usb_driver, USB_DRIVER_NAME);
if (EOK != ret){
KPrintf("board_usb_init UsbDriverInit error %d\n", ret);
return ERROR;
}
/*Attach the usb driver to the usb bus*/
ret = UsbDriverAttachToBus(USB_DRIVER_NAME, USB_BUS_NAME);
if (EOK != ret) {
KPrintf("board_usb_init USEDriverAttachToBus error %d\n", ret);
return ERROR;
}
return ret;
}
/*Attach the usb device to the usb bus*/
static int BoardUsbDevBend(void)
{
x_err_t ret = EOK;
static struct UsbHardwareDevice usb_device;
memset(&usb_device, 0, sizeof(struct UsbHardwareDevice));
usb_device.dev_done = &dev_done;
usb_device.haldev.dev_block_control = UsbControl;
ret = USBDeviceRegister(&usb_device, NONE, USB_DEVICE_NAME);
if (EOK != ret) {
KPrintf("USBDeviceRegister device %s error %d\n", USB_DEVICE_NAME, ret);
return ERROR;
}
ret = USBDeviceAttachToBus(USB_DEVICE_NAME, USB_BUS_NAME);
if (EOK != ret) {
KPrintf("USBDeviceAttachToBus device %s error %d\n", USB_DEVICE_NAME, ret);
return ERROR;
}
return ret;
}
int HwUsbHostInit(void)
{
x_err_t ret = EOK;
static struct UsbBus usb_bus;
memset(&usb_bus, 0, sizeof(struct UsbBus));
static struct UsbDriver usb_driver;
memset(&usb_driver, 0, sizeof(struct UsbDriver));
ret = BoardUsbBusInit(&usb_bus, &usb_driver);
if (EOK != ret) {
KPrintf("BoardUsbBusInit error ret %u\n", ret);
return ERROR;
}
ret = BoardUsbDevBend();
if (EOK != ret) {
KPrintf("BoardUsbDevBend error ret %u\n", ret);
return ERROR;
}
return ret;
}
@@ -0,0 +1,5 @@
SRC_FILES := usb_host_user.c usb_bsp.c
SRC_DIR := usb_host_lib
include $(KERNEL_ROOT)/compiler.mk
@@ -0,0 +1,104 @@
/**
*******************************************************************************
* @file usb/usb_host_msc/source/usb_app_conf.h
* @brief low level driver configuration
@verbatim
Change Logs:
Date Author Notes
2022-03-31 CDT First version
@endverbatim
*******************************************************************************
* Copyright (C) 2022, Xiaohua Semiconductor Co., Ltd. All rights reserved.
*
* This software component is licensed by XHSC under BSD 3-Clause license
* (the "License"); You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
*******************************************************************************
*/
#ifndef __USB_APP_CONF_H__
#define __USB_APP_CONF_H__
/* C binding of definitions if building with C++ compiler */
#ifdef __cplusplus
extern "C"
{
#endif
/*******************************************************************************
* Include files
******************************************************************************/
/* USB MODE CONFIGURATION */
/*
USB_FS_MODE, USB_HS_MODE, USB_HS_EXTERNAL_PHY defined comment
(1) If only defined USB_FS_MODE:
MCU USBFS core work in full speed using internal PHY.
(2) If only defined USB_HS_MODE:
MCU USBHS core work in full speed using internal PHY.
(3) If both defined USB_HS_MODE && USB_HS_EXTERNAL_PHY
MCU USBHS core work in high speed using external PHY.
(4) Other combination:
Not support, forbid!!
*/
//#define USB_HS_MODE
#define USB_FS_MODE
#define USE_HOST_MODE
#ifdef USB_HS_MODE
#define USB_HS_EXTERNAL_PHY
#endif
#ifndef USB_HS_MODE
#ifndef USB_FS_MODE
#error "USB_HS_MODE or USB_FS_MODE should be defined"
#endif
#endif
#ifndef USE_DEVICE_MODE
#ifndef USE_HOST_MODE
#error "USE_DEVICE_MODE or USE_HOST_MODE should be defined"
#endif
#endif
/* USB FIFO CONFIGURATION */
#ifdef USB_FS_MODE
#define RX_FIFO_FS_SIZE (128U)
#define TXH_NP_FS_FIFOSIZ (32U)
#define TXH_P_FS_FIFOSIZ (64U)
#if ((RX_FIFO_FS_SIZE + TXH_NP_FS_FIFOSIZ + TXH_P_FS_FIFOSIZ) > 640U)
#error "The USB max FIFO size is 640 x 4 Bytes!"
#endif
#endif
#ifdef USB_HS_MODE
#define RX_FIFO_HS_SIZE (512U)
#define TXH_NP_HS_FIFOSIZ (128U)
#define TXH_P_HS_FIFOSIZ (256U)
#if ((RX_FIFO_FS_SIZE + TXH_NP_FS_FIFOSIZ + TXH_P_FS_FIFOSIZ) > 2048U)
#error "The USB max FIFO size is 2048 x 4 Bytes!"
#endif
#endif
/* FUNCTION CONFIGURATION */
#define USBH_MAX_NUM_INTERFACES (3U)
#define USBH_MAX_NUM_ENDPOINTS (2U)
/* CONFIGURATION FOR MSC */
#define USBH_MSC_MPS_SIZE (0x40U)
//#define USB_MSC_FAT_VALID
#ifdef __cplusplus
}
#endif
#endif /* __USB_APP_CONF_H__ */
/*******************************************************************************
* EOF (not truncated)
******************************************************************************/
@@ -0,0 +1,147 @@
/**
*******************************************************************************
* @file usb/usb_host_msc/source/usb_bsp.c
* @brief BSP function for USB example
@verbatim
Change Logs:
Date Author Notes
2022-03-31 CDT First version
@endverbatim
*******************************************************************************
* Copyright (C) 2022, Xiaohua Semiconductor Co., Ltd. All rights reserved.
*
* This software component is licensed by XHSC under BSD 3-Clause license
* (the "License"); You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
*******************************************************************************
*/
/**
* @file usb_bsp.c
* @brief support hc32f4a0-board usb bsp function
* @version 2.0
* @author AIIT XUOS Lab
* @date 2022-11-08
*/
/*************************************************
File name: usb_bsp.c
Description: support hc32f4a0-board usb bsp function
Others:
History:
1. Date: 2022-11-08
Author: AIIT XUOS Lab
Modification:
1. support hc32f4a0-board usb IO configure
2. support hc32f4a0-board usb irq define
*************************************************/
#include <device.h>
#include "usb_bsp.h"
#include <usb_host_int.h>
extern usb_core_instance usb_app_instance;
/* USBFS Core*/
#define USB_DP_PORT (GPIO_PORT_A)
#define USB_DP_PIN (GPIO_PIN_12)
#define USB_DM_PORT (GPIO_PORT_A)
#define USB_DM_PIN (GPIO_PIN_11)
#define USB_DRVVBUS_PORT (GPIO_PORT_C)
#define USB_DRVVBUS_PIN (GPIO_PIN_09)
#define USB_VBUSDET_PORT (GPIO_PORT_A)
#define USB_VBUSDET_PIN (GPIO_PIN_09)
#define USB_OC_PORT (GPIO_PORT_D)
#define USB_OC_PIN (GPIO_PIN_15)
//USB HOST ISR
static void USB_IRQ_Handler(void)
{
x_base lock = 0;
lock = DISABLE_INTERRUPT();
usb_host_isr(&usb_app_instance);
ENABLE_INTERRUPT(lock);
}
void usb_bsp_init(usb_core_instance *pdev)
{
stc_gpio_init_t stcGpioCfg;
/* USB clock source configurate */
CLK_SetUSBClockSrc(CLK_USBCLK_SYSCLK_DIV5);
(void)GPIO_StructInit(&stcGpioCfg);
#ifdef USB_FS_MODE
stcGpioCfg.u16PinAttr = PIN_ATTR_ANALOG;
(void)GPIO_Init(USB_DM_PORT, USB_DM_PIN, &stcGpioCfg);
(void)GPIO_Init(USB_DP_PORT, USB_DP_PIN, &stcGpioCfg);
GPIO_SetFunc(USB_DRVVBUS_PORT, USB_DRVVBUS_PIN, GPIO_FUNC_10); /* VBUS */
FCG_Fcg1PeriphClockCmd(FCG1_PERIPH_USBFS, ENABLE);
#endif
}
void usb_bsp_nvicconfig(void)
{
stc_irq_signin_config_t stcIrqRegiConf;
/* Register INT_SRC_USBFS_GLB Int to Vect.No.030 */
stcIrqRegiConf.enIRQn = INT030_IRQn;
/* Select interrupt function */
#ifdef USB_FS_MODE
stcIrqRegiConf.enIntSrc = INT_SRC_USBFS_GLB;
#else
stcIrqRegiConf.enIntSrc = INT_SRC_USBHS_GLB;
#endif
/* Callback function */
stcIrqRegiConf.pfnCallback = &USB_IRQ_Handler;
/* Registration IRQ */
(void)INTC_IrqSignIn(&stcIrqRegiConf);
/* Clear Pending */
NVIC_ClearPendingIRQ(stcIrqRegiConf.enIRQn);
/* Set priority */
NVIC_SetPriority(stcIrqRegiConf.enIRQn, DDL_IRQ_PRIO_15);
/* Enable NVIC */
NVIC_EnableIRQ(stcIrqRegiConf.enIRQn);
}
void usb_udelay(const uint32_t usec)
{
__IO uint32_t i;
uint32_t j;
j = (HCLK_VALUE + 1000000UL - 1UL) / 1000000UL * usec;
for (i = 0UL; i < j; i++) {
}
}
void usb_mdelay(const uint32_t msec)
{
usb_udelay(msec * 1000);
}
/**
* @brief Configures the IO for the Vbus and OverCurrent
* @param [in] pdev device instance
* @retval None
*/
void usb_bsp_cfgvbus(LL_USB_TypeDef *USBx)
{
}
/**
* @brief Drive vbus
* @param [in] pdev device instance
* @param [in] state the vbus state it would be.
* @retval None
*/
void usb_bsp_drivevbus(LL_USB_TypeDef *USBx, uint8_t state)
{
}
@@ -0,0 +1,104 @@
/**
*******************************************************************************
* @file usb/usb_host_msc/source/usb_bsp.h
* @brief Head file for usb_bsp.c
@verbatim
Change Logs:
Date Author Notes
2022-03-31 CDT First version
@endverbatim
*******************************************************************************
* Copyright (C) 2022, Xiaohua Semiconductor Co., Ltd. All rights reserved.
*
* This software component is licensed by XHSC under BSD 3-Clause license
* (the "License"); You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
*******************************************************************************
*/
/**
* @file usb_bsp.h
* @brief support hc32f4a0-board usb bsp function
* @version 2.0
* @author AIIT XUOS Lab
* @date 2022-11-08
*/
/*************************************************
File name: usb_bsp.h
Description: support hc32f4a0-board usb bsp function
Others:
History:
1. Date: 2022-11-08
Author: AIIT XUOS Lab
Modification:
*************************************************/
#ifndef USB_BSP_H
#define USB_BSP_H
/* C binding of definitions if building with C++ compiler */
#ifdef __cplusplus
extern "C"
{
#endif
/*******************************************************************************
* Include files
******************************************************************************/
#include <usb_lib.h>
/**
* @addtogroup HC32F4A0_DDL_Applications
* @{
*/
/**
* @addtogroup USB_Host_Msc
* @{
*/
/*******************************************************************************
* Global type definitions ('typedef')
******************************************************************************/
/*******************************************************************************
* Global pre-processor symbols/macros ('#define')
******************************************************************************/
/*******************************************************************************
* Global variable definitions ('extern')
******************************************************************************/
/*******************************************************************************
Global function prototypes (definition in C source)
******************************************************************************/
extern void usb_bsp_init(usb_core_instance *pdev);
extern void usb_udelay(const uint32_t usec);
extern void usb_mdelay(const uint32_t msec);
extern void usb_bsp_nvicconfig(void);
#ifdef USE_HOST_MODE
extern void usb_bsp_cfgvbus(LL_USB_TypeDef *USBx);
extern void usb_bsp_drivevbus(LL_USB_TypeDef *USBx, uint8_t state);
#endif
/**
* @}
*/
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* __USB_BSP_H__ */
/*******************************************************************************
* EOF (not truncated)
******************************************************************************/
@@ -0,0 +1,3 @@
SRC_DIR := host_class host_core
include $(KERNEL_ROOT)/compiler.mk
@@ -0,0 +1,3 @@
SRC_DIR := msc
include $(KERNEL_ROOT)/compiler.mk
@@ -0,0 +1,3 @@
SRC_FILES := usb_host_msc_bot.c usb_host_msc_class.c usb_host_msc_scsi.c
include $(KERNEL_ROOT)/compiler.mk
@@ -0,0 +1,449 @@
/**
*******************************************************************************
* @file usb_host_msc_bot.c
* @brief mass storage related functions
@verbatim
Change Logs:
Date Author Notes
2022-03-31 CDT First version
@endverbatim
*******************************************************************************
* Copyright (C) 2022, Xiaohua Semiconductor Co., Ltd. All rights reserved.
*
* This software component is licensed by XHSC under BSD 3-Clause license
* (the "License"); You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
*******************************************************************************
*/
/*******************************************************************************
* Include files
******************************************************************************/
#include "usb_host_msc_class.h"
#include "usb_host_msc_scsi.h"
#include "usb_host_msc_bot.h"
#include "usb_host_ctrltrans.h"
#include "usb_host_def.h"
#include "usb_host_int.h"
#include "usb_host_driver.h"
/**
* @addtogroup LL_USB_LIB
* @{
*/
/**
* @addtogroup LL_USB_HOST_CLASS
* @{
*/
/**
* @addtogroup LL_USB_HOST_MSC USB Host MSC
* @{
*/
/*******************************************************************************
* Local type definitions ('typedef')
******************************************************************************/
/*******************************************************************************
* Local pre-processor symbols/macros ('#define')
******************************************************************************/
/*******************************************************************************
* Global variable definitions (declared in header file with 'extern')
******************************************************************************/
#ifdef USB_INTERNAL_DMA_ENABLED
#if defined ( __ICCARM__ ) /*!< IAR Compiler */
#pragma data_alignment=4
#endif
#endif /* USB_INTERNAL_DMA_ENABLED */
__USB_ALIGN_BEGIN HOST_CSW_PACKET_TypeDef USBH_MSC_CSWData;
USB_HOST_BOTXFER_TypeDef USBH_MSC_BOTXferParam;
/*******************************************************************************
* Local function prototypes ('static')
******************************************************************************/
/*******************************************************************************
* Local variable definitions ('static')
******************************************************************************/
#ifdef USB_INTERNAL_DMA_ENABLED
#if defined ( __ICCARM__ ) /*!< IAR Compiler */
#pragma data_alignment=4
#endif
#endif /* USB_INTERNAL_DMA_ENABLED */
__USB_ALIGN_BEGIN HostCBWPkt_TypeDef USBH_MSC_CBWData;
static uint32_t BOTStallErrorCount; /* Keeps count of STALL Error Cases*/
/*******************************************************************************
* Function implementation - global ('extern') and local ('static')
******************************************************************************/
/**
* @brief initializes original state of the mass storage parameters
* @param [in] pdev device instance
* @retval None
*/
void usb_host_msc_init(usb_core_instance *pdev)
{
if (host_driver_ifdevconnected(pdev) != 0UL) {
USBH_MSC_CBWData.field.CBWSignature = HOST_MSC_BOT_CBW_SIGNATURE;
USBH_MSC_CBWData.field.CBWTag = HOST_MSC_BOT_CBW_TAG;
USBH_MSC_CBWData.field.CBWLUN = 0U;
USBH_MSC_BOTXferParam.CmdStateMachine = USB_HOST_MSC_CMD_SEND;
}
BOTStallErrorCount = 0UL;
MSCErrorCount = 0U;
}
/**
* @brief manages the different states of BOT transfer and updates the
* status for the upper layer.
* @param [in] pdev device instance
* @param [in] phost host state set
* @retval None
*/
void usb_host_msc_botxferprocess(usb_core_instance *pdev, USBH_HOST *phost)
{
uint8_t xferDirection, index;
static uint32_t remainingDataLength;
static uint8_t *datapointer, *datapointer_prev;
static uint8_t error_direction;
HOST_STATUS status;
HOST_CH_XFER_STATE URB_Status;
if (host_driver_ifdevconnected(pdev) != 0UL) {
switch (USBH_MSC_BOTXferParam.BOTState) {
case HOST_MSC_SEND_CBW:
/* send a CBW */
usb_host_sendbulkdata(pdev,
&USBH_MSC_CBWData.CBWArray[0],
HOST_MSC_BOT_CBW_PACKET_LENGTH,
MSC_Machine.hc_num_out);
USBH_MSC_BOTXferParam.BOTStateBkp = HOST_MSC_SEND_CBW;
USBH_MSC_BOTXferParam.BOTState = HOST_MSC_SENT_CBW;
break;
case HOST_MSC_SENT_CBW:
URB_Status = host_driver_getxferstate(pdev, MSC_Machine.hc_num_out);
switch (URB_Status) {
case HOST_CH_XFER_DONE:
BOTStallErrorCount = 0U;
USBH_MSC_BOTXferParam.BOTStateBkp = HOST_MSC_SENT_CBW;
/* If the CBW packet is sent successful, then update the state */
xferDirection = (USBH_MSC_CBWData.field.CBWFlags & USB_REQ_DIR_MASK);
if (USBH_MSC_CBWData.field.CBWTransferLength != 0UL) {
remainingDataLength = USBH_MSC_CBWData.field.CBWTransferLength ;
datapointer = USBH_MSC_BOTXferParam.pRxTxBuff;
datapointer_prev = datapointer;
/* If there has data transfer stage, update the direction whether it is D2H or H2D */
if (xferDirection == USB_D2H) {
USBH_MSC_BOTXferParam.BOTState = HOST_MSC_BOT_DATAIN_STATE;
} else {
USBH_MSC_BOTXferParam.BOTState = HOST_MSC_BOT_DATAOUT_STATE;
}
} else {
/* If there has not data transfer stage also update the state */
USBH_MSC_BOTXferParam.BOTState = HOST_MSC_RECEIVE_CSW_STATE;
}
break;
case HOST_CH_XFER_UNREADY:
USBH_MSC_BOTXferParam.BOTState = USBH_MSC_BOTXferParam.BOTStateBkp;
break;
case HOST_CH_XFER_STALL:
error_direction = HOST_MSC_DIR_OUT;
USBH_MSC_BOTXferParam.BOTState = HOST_MSC_BOT_ERROR_OUT;
break;
default:
break;
}
break;
case HOST_MSC_BOT_DATAIN_STATE:
URB_Status = host_driver_getxferstate(pdev, MSC_Machine.hc_num_in);
if ((URB_Status == HOST_CH_XFER_DONE) \
|| (USBH_MSC_BOTXferParam.BOTStateBkp != HOST_MSC_BOT_DATAIN_STATE)) {
BOTStallErrorCount = 0U;
USBH_MSC_BOTXferParam.BOTStateBkp = HOST_MSC_BOT_DATAIN_STATE;
if (remainingDataLength > MSC_Machine.MSC_BulkInEpSize) {
usb_host_recvbulkdata(pdev,
datapointer,
MSC_Machine.MSC_BulkInEpSize,
MSC_Machine.hc_num_in);
remainingDataLength -= MSC_Machine.MSC_BulkInEpSize;
datapointer = datapointer + MSC_Machine.MSC_BulkInEpSize;
} else if (remainingDataLength == 0UL) {
/* If value was 0, and successful transfer, then change the state */
USBH_MSC_BOTXferParam.BOTState = HOST_MSC_RECEIVE_CSW_STATE;
} else {
usb_host_recvbulkdata(pdev,
datapointer,
(uint16_t)remainingDataLength,
MSC_Machine.hc_num_in);
remainingDataLength = 0UL;
}
} else if (URB_Status == HOST_CH_XFER_STALL) {
error_direction = HOST_MSC_DIR_IN;
USBH_MSC_BOTXferParam.BOTState = HOST_MSC_BOT_ERROR_IN;
USBH_MSC_BOTXferParam.BOTStateBkp = HOST_MSC_RECEIVE_CSW_STATE;
} else {
;
}
break;
case HOST_MSC_BOT_DATAOUT_STATE:
URB_Status = host_driver_getxferstate(pdev, MSC_Machine.hc_num_out);
if (URB_Status == HOST_CH_XFER_DONE) {
BOTStallErrorCount = 0UL;
USBH_MSC_BOTXferParam.BOTStateBkp = HOST_MSC_BOT_DATAOUT_STATE;
if (remainingDataLength > MSC_Machine.MSC_BulkOutEpSize) {
usb_host_sendbulkdata(pdev,
datapointer,
MSC_Machine.MSC_BulkOutEpSize,
MSC_Machine.hc_num_out);
datapointer_prev = datapointer;
datapointer = datapointer + MSC_Machine.MSC_BulkOutEpSize;
remainingDataLength = remainingDataLength - MSC_Machine.MSC_BulkOutEpSize;
} else if (remainingDataLength == 0UL) {
USBH_MSC_BOTXferParam.BOTState = HOST_MSC_RECEIVE_CSW_STATE;
} else {
usb_host_sendbulkdata(pdev,
datapointer,
(uint16_t)remainingDataLength,
MSC_Machine.hc_num_out);
remainingDataLength = 0UL;
}
} else if (URB_Status == HOST_CH_XFER_UNREADY) {
if (datapointer != datapointer_prev) {
usb_host_sendbulkdata(pdev,
(datapointer - MSC_Machine.MSC_BulkOutEpSize),
MSC_Machine.MSC_BulkOutEpSize,
MSC_Machine.hc_num_out);
} else {
usb_host_sendbulkdata(pdev,
datapointer,
MSC_Machine.MSC_BulkOutEpSize,
MSC_Machine.hc_num_out);
}
} else if (URB_Status == HOST_CH_XFER_STALL) {
error_direction = HOST_MSC_DIR_OUT;
USBH_MSC_BOTXferParam.BOTState = HOST_MSC_BOT_ERROR_OUT;
USBH_MSC_BOTXferParam.BOTStateBkp = HOST_MSC_RECEIVE_CSW_STATE;
} else {
;
}
break;
case HOST_MSC_RECEIVE_CSW_STATE:
USBH_MSC_BOTXferParam.BOTStateBkp = HOST_MSC_RECEIVE_CSW_STATE;
USBH_MSC_BOTXferParam.pRxTxBuff = USBH_MSC_CSWData.CSWArray;
USBH_MSC_BOTXferParam.DataLength = HOST_MSC_CSW_MAX_LENGTH;
for (index = 0U; index < HOST_MSC_CSW_LENGTH; index++) {
USBH_MSC_CSWData.CSWArray[index] = 0U;
}
USBH_MSC_CSWData.CSWArray[0] = 0U;
usb_host_recvbulkdata(pdev,
USBH_MSC_BOTXferParam.pRxTxBuff,
HOST_MSC_CSW_MAX_LENGTH,
MSC_Machine.hc_num_in);
USBH_MSC_BOTXferParam.BOTState = HOST_MSC_DECODE_CSW;
break;
case HOST_MSC_DECODE_CSW:
URB_Status = host_driver_getxferstate(pdev, MSC_Machine.hc_num_in);
if (URB_Status == HOST_CH_XFER_DONE) {
BOTStallErrorCount = 0UL;
USBH_MSC_BOTXferParam.BOTStateBkp = HOST_MSC_RECEIVE_CSW_STATE;
USBH_MSC_BOTXferParam.MSCState = USBH_MSC_BOTXferParam.MSCStateCurrent ;
USBH_MSC_BOTXferParam.BOTXferStatus = usb_host_msc_cswdecode(pdev, phost);
} else if (URB_Status == HOST_CH_XFER_STALL) {
error_direction = HOST_MSC_DIR_IN;
USBH_MSC_BOTXferParam.BOTState = HOST_MSC_BOT_ERROR_IN;
} else {
;
}
break;
case HOST_MSC_BOT_ERROR_IN:
status = usb_host_msc_botabort(pdev, phost, HOST_MSC_DIR_IN);
if (status == HSTATUS_OK) {
if (error_direction == HOST_MSC_BOTH_DIR) {
USBH_MSC_BOTXferParam.BOTState = HOST_MSC_BOT_ERROR_OUT;
} else {
/* switch back to the original state */
USBH_MSC_BOTXferParam.BOTState = USBH_MSC_BOTXferParam.BOTStateBkp;
}
} else if (status == HSTATUS_UNRECOVERED_ERROR) {
/* This means that there is a STALL Error limit, Do Reset Recovery */
USBH_MSC_BOTXferParam.BOTXferStatus = (uint8_t)USB_HOST_MSC_PHASE_ERROR;
} else {
;
}
break;
case HOST_MSC_BOT_ERROR_OUT:
status = usb_host_msc_botabort(pdev, phost, HOST_MSC_DIR_OUT);
if (status == HSTATUS_OK) {
/* switch back to the original state */
USBH_MSC_BOTXferParam.BOTState = USBH_MSC_BOTXferParam.BOTStateBkp;
} else if (status == HSTATUS_UNRECOVERED_ERROR) {
/* This means that there is a STALL Error limit, Do Reset Recovery */
USBH_MSC_BOTXferParam.BOTXferStatus = (uint8_t)USB_HOST_MSC_PHASE_ERROR;
} else {
;
}
break;
default:
break;
}
}
}
/**
* @brief manages the different Error handling for STALL
* @param [in] pdev device instance
* @param [in] phost host state set
* @param [in] direction IN / OUT
* @retval None
*/
HOST_STATUS usb_host_msc_botabort(usb_core_instance *pdev, USBH_HOST *phost, uint8_t direction)
{
HOST_STATUS status;
status = HSTATUS_BUSY;
switch (direction) {
case HOST_MSC_DIR_IN:
/* send ClrFeture on Bulk IN endpoint */
status = usb_host_clrfeature(pdev,
phost,
MSC_Machine.MSC_BulkInEp,
MSC_Machine.hc_num_in);
break;
case HOST_MSC_DIR_OUT:
/* send ClrFeature on Bulk OUT endpoint */
status = usb_host_clrfeature(pdev,
phost,
MSC_Machine.MSC_BulkOutEp,
MSC_Machine.hc_num_out);
break;
default:
break;
}
BOTStallErrorCount++;
if (BOTStallErrorCount > 4UL) {
status = HSTATUS_UNRECOVERED_ERROR;
}
return status;
}
/**
* @brief Decodes the CSW received by the device and updates the same to upper layer
* @param [in] pdev device instance
* @param [in] phost host state set
* @retval On success USB_HOST_MSC_OK, on failure USB_HOST_MSC_FAIL
*/
uint8_t usb_host_msc_cswdecode(usb_core_instance *pdev, USBH_HOST *phost)
{
USB_HOST_MSC_STATUS status;
uint32_t dataXferCount;
status = USB_HOST_MSC_FAIL;
if (host_driver_ifdevconnected(pdev) != 0UL) {
dataXferCount = host_driver_getxfercnt(pdev, MSC_Machine.hc_num_in);
if (dataXferCount != HOST_MSC_CSW_LENGTH) {
/*(4) Hi > Dn (Host expects to receive data from the device,
Device intends to transfer no data)
(5) Hi > Di (Host expects to receive data from the device,
Device intends to send data to the host)
(9) Ho > Dn (Host expects to send data to the device,
Device intends to transfer no data)
(11) Ho > Do (Host expects to send data to the device,
Device intends to receive data from the host)*/
status = USB_HOST_MSC_PHASE_ERROR;
} else {
/* CSW length is Correct */
/* Check validity of the CSW Signature and CSWStatus */
if (USBH_MSC_CSWData.field.dCSWSignature == HOST_MSC_BOT_CSW_SIGNATURE) {
/* Check Condition 1. dCSWSignature is equal to 53425355h */
if (USBH_MSC_CSWData.field.dCSWTag == USBH_MSC_CBWData.field.CBWTag) {
/* Check Condition 3. dCSWTag matches the dCBWTag from the
corresponding CBW */
if (USBH_MSC_CSWData.field.dCSWStatus == (uint8_t)USB_HOST_MSC_OK) {
/* Refer to USB Mass-Storage Class : BOT (www.usb.org)
Hn Host expects no data transfers
Hi Host expects to receive data from the device
Ho Host expects to send data to the device
Dn Device intends to transfer no data
Di Device intends to send data to the host
Do Device intends to receive data from the host
Section 6.7
(1) Hn = Dn (Host expects no data transfers,
Device intends to transfer no data)
(6) Hi = Di (Host expects to receive data from the device,
Device intends to send data to the host)
(12) Ho = Do (Host expects to send data to the device,
Device intends to receive data from the host)
*/
status = USB_HOST_MSC_OK;
} else if (USBH_MSC_CSWData.field.dCSWStatus == (uint8_t)USB_HOST_MSC_FAIL) {
status = USB_HOST_MSC_FAIL;
} else if (USBH_MSC_CSWData.field.dCSWStatus == (uint8_t)USB_HOST_MSC_PHASE_ERROR) {
/* Refer to USB Mass-Storage Class : BOT (www.usb.org)
Section 6.7
(2) Hn < Di ( Host expects no data transfers,
Device intends to send data to the host)
(3) Hn < Do ( Host expects no data transfers,
Device intends to receive data from the host)
(7) Hi < Di ( Host expects to receive data from the device,
Device intends to send data to the host)
(8) Hi <> Do ( Host expects to receive data from the device,
Device intends to receive data from the host)
(10) Ho <> Di (Host expects to send data to the device,
Di Device intends to send data to the host)
(13) Ho < Do (Host expects to send data to the device,
Device intends to receive data from the host)
*/
status = USB_HOST_MSC_PHASE_ERROR;
} else {
;
}
}
} else {
status = USB_HOST_MSC_PHASE_ERROR;
}
}
}
USBH_MSC_BOTXferParam.BOTXferStatus = (uint8_t)status;
return (uint8_t)status;
}
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/*******************************************************************************
* EOF (not truncated)
******************************************************************************/
@@ -0,0 +1,162 @@
/**
*******************************************************************************
* @file usb_host_msc_bot.h
* @brief Head file for usb_host_msc_bot.c
@verbatim
Change Logs:
Date Author Notes
2022-03-31 CDT First version
@endverbatim
*******************************************************************************
* Copyright (C) 2022, Xiaohua Semiconductor Co., Ltd. All rights reserved.
*
* This software component is licensed by XHSC under BSD 3-Clause license
* (the "License"); You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
*******************************************************************************
*/
#ifndef __USB_HOST_MSC_BOT_H__
#define __USB_HOST_MSC_BOT_H__
/* C binding of definitions if building with C++ compiler */
#ifdef __cplusplus
extern "C"
{
#endif
/*******************************************************************************
* Include files
******************************************************************************/
#include "usb_host_stdreq.h"
/**
* @addtogroup LL_USB_LIB
* @{
*/
/**
* @addtogroup LL_USB_HOST_CLASS
* @{
*/
/**
* @addtogroup LL_USB_HOST_MSC
* @{
*/
/*******************************************************************************
* Global type definitions ('typedef')
******************************************************************************/
typedef union _USBH_CBW_Block {
struct __CBW {
uint32_t CBWSignature;
uint32_t CBWTag;
uint32_t CBWTransferLength;
uint8_t CBWFlags;
uint8_t CBWLUN;
uint8_t CBWLength;
uint8_t CBWCB[16];
} field;
uint8_t CBWArray[31];
} HostCBWPkt_TypeDef;
typedef struct {
uint8_t MSCState;
uint8_t MSCStateBkp;
uint8_t MSCStateCurrent;
uint8_t CmdStateMachine;
uint8_t BOTState;
uint8_t BOTStateBkp;
uint8_t *pRxTxBuff;
uint16_t DataLength;
uint8_t BOTXferStatus;
} USB_HOST_BOTXFER_TypeDef;
typedef union {
struct {
uint32_t dCSWSignature;
uint32_t dCSWTag;
uint32_t dCSWDataResidue;
uint8_t dCSWStatus;
} field;
uint8_t CSWArray[13];
} HOST_CSW_PACKET_TypeDef;
/*******************************************************************************
* Global pre-processor symbols/macros ('#define')
******************************************************************************/
#define HOST_MSC_BOT_INIT_STATE (0U)
#define HOST_MSC_BOT_RESET (1U)
#define HOST_MSC_GET_MAX_LUN (2U)
#define HOST_MSC_TEST_UNIT_READY (3U)
#define HOST_MSC_READ_CAPACITY10 (4U)
#define HOST_MSC_MODE_SENSE6 (5U)
#define HOST_MSC_REQUEST_SENSE (6U)
#define HOST_MSC_BOT_USB_TRANSFERS (7U)
#define HOST_MSC_DEFAULT_APPLI_STATE (8U)
#define HOST_MSC_CTRL_ERROR_STATE (9U)
#define HOST_MSC_UNRECOVERED_STATE (10U)
#define HOST_MSC_SEND_CBW (1U)
#define HOST_MSC_SENT_CBW (2U)
#define HOST_MSC_BOT_DATAIN_STATE (3U)
#define HOST_MSC_BOT_DATAOUT_STATE (4U)
#define HOST_MSC_RECEIVE_CSW_STATE (5U)
#define HOST_MSC_DECODE_CSW (6U)
#define HOST_MSC_BOT_ERROR_IN (7U)
#define HOST_MSC_BOT_ERROR_OUT (8U)
#define HOST_MSC_BOT_CBW_SIGNATURE (0x43425355UL)
#define HOST_MSC_BOT_CBW_TAG (0x20304050UL)
#define HOST_MSC_BOT_CSW_SIGNATURE (0x53425355UL)
#define HOST_MSC_CSW_DATA_LENGTH (13U)
#define HOST_MSC_BOT_CBW_PACKET_LENGTH (31U)
#define HOST_MSC_CSW_LENGTH (13U)
#define HOST_MSC_CSW_MAX_LENGTH (63U)
#define HOST_MSC_DIR_IN (0U)
#define HOST_MSC_DIR_OUT (1U)
#define HOST_MSC_BOTH_DIR (2U)
#define HOST_MSC_PAGE_LENGTH (512UL)
#define CBW_CB_LENGTH (16U)
#define CBW_LENGTH (10U)
#define CBW_LENGTH_TEST_UNIT_READY (6U)
/*******************************************************************************
* Global variable definitions ('extern')
******************************************************************************/
extern USB_HOST_BOTXFER_TypeDef USBH_MSC_BOTXferParam;
extern HostCBWPkt_TypeDef USBH_MSC_CBWData;
extern HOST_CSW_PACKET_TypeDef USBH_MSC_CSWData;
/*******************************************************************************
Global function prototypes (definition in C source)
******************************************************************************/
extern void usb_host_msc_init(usb_core_instance *pdev);
extern void usb_host_msc_botxferprocess(usb_core_instance *pdev, USBH_HOST *phost);
extern uint8_t usb_host_msc_cswdecode(usb_core_instance *pdev, USBH_HOST *phost);
extern HOST_STATUS usb_host_msc_botabort(usb_core_instance *pdev, USBH_HOST *phost, uint8_t direction);
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* __USB_HOST_MSC_BOT_H__ */
/*******************************************************************************
* EOF (not truncated)
******************************************************************************/
@@ -0,0 +1,395 @@
/**
*******************************************************************************
* @file usb_host_msc_class.c
* @brief The MSC class driver functions
@verbatim
Change Logs:
Date Author Notes
2022-03-31 CDT First version
@endverbatim
*******************************************************************************
* Copyright (C) 2022, Xiaohua Semiconductor Co., Ltd. All rights reserved.
*
* This software component is licensed by XHSC under BSD 3-Clause license
* (the "License"); You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
*******************************************************************************
*/
/*******************************************************************************
* Include files
******************************************************************************/
#include "usb_host_msc_class.h"
#include "usb_host_msc_scsi.h"
#include "usb_host_msc_bot.h"
#include "usb_host_core.h"
#include "usb_host_driver.h"
/**
* @addtogroup LL_USB_LIB
* @{
*/
/**
* @addtogroup LL_USB_HOST_CLASS
* @{
*/
/**
* @addtogroup LL_USB_HOST_MSC
* @{
*/
/*******************************************************************************
* Local type definitions ('typedef')
******************************************************************************/
/*******************************************************************************
* Local pre-processor symbols/macros ('#define')
******************************************************************************/
#define USBH_MSC_ERROR_RETRY_LIMIT (10U)
/*******************************************************************************
* Local function prototypes ('static')
******************************************************************************/
HOST_STATUS usb_host_msc_itfinit(usb_core_instance *pdev, void *phost);
void usb_host_msc_itfdeinit(usb_core_instance *pdev);
HOST_STATUS usb_host_msc_process(usb_core_instance *pdev, void *phost);
HOST_STATUS usb_host_msc_classreq(usb_core_instance *pdev, void *phost);
HOST_STATUS usb_host_msc_bot_reset(usb_core_instance *pdev, USBH_HOST *phost);
HOST_STATUS usb_host_msc_maxlun_get(usb_core_instance *pdev, USBH_HOST *phost);
void usb_host_msc_error_process(USB_HOST_MSC_STATUS status);
/*******************************************************************************
* Global variable definitions (declared in header file with 'extern')
******************************************************************************/
#ifdef USB_INTERNAL_DMA_ENABLED
#if defined ( __ICCARM__ ) /*!< IAR Compiler */
#pragma data_alignment=4
#endif
#endif /* USB_INTERNAL_DMA_ENABLED */
__USB_ALIGN_BEGIN MSC_Machine_TypeDef MSC_Machine;
#ifdef USB_INTERNAL_DMA_ENABLED
#if defined ( __ICCARM__ ) /*!< IAR Compiler */
#pragma data_alignment=4
#endif
#endif /* USB_INTERNAL_DMA_ENABLED */
uint8_t MSCErrorCount = 0U;
usb_host_class_callback_func USBH_MSC_cb = {
&usb_host_msc_itfinit,
&usb_host_msc_itfdeinit,
&usb_host_msc_classreq,
&usb_host_msc_process,
};
/*******************************************************************************
* Local variable definitions ('static')
******************************************************************************/
/*******************************************************************************
* Function implementation - global ('extern') and local ('static')
******************************************************************************/
/**
* @brief This request is used to issue a request to reset the msc device and
* its related interface. This class-specific request shall prepare the
* device for the next CBW from the host.
* @param [in] pdev device instance
* @param [in] phost host state set
* @retval status define by HOST_STATUS
*/
HOST_STATUS usb_host_msc_bot_reset(usb_core_instance *pdev, USBH_HOST *phost)
{
phost->ctrlparam.setup.b.bmRequestType = USB_H2D | USB_REQ_TYPE_CLASS | \
USB_REQ_RECIPIENT_INTERFACE;
phost->ctrlparam.setup.b.bRequest = USB_REQ_BOT_RESET;
phost->ctrlparam.setup.b.wValue.w = 0U;
phost->ctrlparam.setup.b.wIndex.w = 0U;
phost->ctrlparam.setup.b.wLength.w = 0U;
return usb_host_ctrlreq(pdev, phost, NULL, 0U);
}
/**
* @brief this request is used to issue a request to get the max logic unit of
* the msc device.
* @param [in] pdev device instance
* @param [in] phost host state set
* @retval status defined by HOST_STATUS
*/
HOST_STATUS usb_host_msc_maxlun_get(usb_core_instance *pdev, USBH_HOST *phost)
{
phost->ctrlparam.setup.b.bmRequestType = USB_D2H | USB_REQ_TYPE_CLASS | \
USB_REQ_RECIPIENT_INTERFACE;
phost->ctrlparam.setup.b.bRequest = USB_REQ_GET_MAX_LUN;
phost->ctrlparam.setup.b.wValue.w = 0U;
phost->ctrlparam.setup.b.wIndex.w = 0U;
phost->ctrlparam.setup.b.wLength.w = 1U;
return usb_host_ctrlreq(pdev, phost, MSC_Machine.buff, 1U);
}
/**
* @brief The function is used for handling errors during processing the MSC
* state machine
* @param [in] status
* @retval None
*/
void usb_host_msc_error_process(USB_HOST_MSC_STATUS status)
{
switch (status) {
case USB_HOST_MSC_FAIL:
MSCErrorCount++;
if (MSCErrorCount < USBH_MSC_ERROR_RETRY_LIMIT) {
/* Try MSC level error recovery, Issue the request Sense to get
driver error reason */
USBH_MSC_BOTXferParam.MSCState = HOST_MSC_REQUEST_SENSE;
USBH_MSC_BOTXferParam.CmdStateMachine = USB_HOST_MSC_CMD_SEND;
} else {
/* Error trials exceeded the limit, go to unrecovered state */
USBH_MSC_BOTXferParam.MSCState = HOST_MSC_UNRECOVERED_STATE;
}
break;
case USB_HOST_MSC_PHASE_ERROR:
/* Phase error, Go to Unrecoovered state */
USBH_MSC_BOTXferParam.MSCState = HOST_MSC_UNRECOVERED_STATE;
break;
default:
break;
}
}
/**
* @brief Interface initialization for msc class application, the channels for
* the IN and OUT EP will be distributed.
* @param [in] pdev device instance
* @param [in] phost host state set
* @retval status defined by HOST_STATUS
*/
HOST_STATUS usb_host_msc_itfinit(usb_core_instance *pdev, void *phost)
{
USBH_HOST *pphost = phost;
if ((pphost->device_prop.devitfdesc[0].bInterfaceClass == MSC_CLASS) && \
(pphost->device_prop.devitfdesc[0].bInterfaceProtocol == MSC_PROTOCOL)) {
if ((pphost->device_prop.devepdesc[0][0].bEndpointAddress & 0x80U) == 0x80U) {
MSC_Machine.MSC_BulkInEp = (pphost->device_prop.devepdesc[0][0].bEndpointAddress);
MSC_Machine.MSC_BulkInEpSize = pphost->device_prop.devepdesc[0][0].wMaxPacketSize;
} else {
MSC_Machine.MSC_BulkOutEp = (pphost->device_prop.devepdesc[0][0].bEndpointAddress);
MSC_Machine.MSC_BulkOutEpSize = pphost->device_prop.devepdesc[0] [0].wMaxPacketSize;
}
if ((pphost->device_prop.devepdesc[0][1].bEndpointAddress & 0x80U) == 0x80U) {
MSC_Machine.MSC_BulkInEp = (pphost->device_prop.devepdesc[0][1].bEndpointAddress);
MSC_Machine.MSC_BulkInEpSize = pphost->device_prop.devepdesc[0][1].wMaxPacketSize;
} else {
MSC_Machine.MSC_BulkOutEp = (pphost->device_prop.devepdesc[0][1].bEndpointAddress);
MSC_Machine.MSC_BulkOutEpSize = pphost->device_prop.devepdesc[0][1].wMaxPacketSize;
}
/* distribute the channels for the EPs */
MSC_Machine.hc_num_out = usb_host_distrch(pdev, MSC_Machine.MSC_BulkOutEp);
MSC_Machine.hc_num_in = usb_host_distrch(pdev, MSC_Machine.MSC_BulkInEp);
/* open the channels that have distributed */
usb_host_chopen(pdev,
MSC_Machine.hc_num_out,
pphost->device_prop.devaddr,
pphost->device_prop.devspeed,
EP_TYPE_BULK,
MSC_Machine.MSC_BulkOutEpSize);
usb_host_chopen(pdev,
MSC_Machine.hc_num_in,
pphost->device_prop.devaddr,
pphost->device_prop.devspeed,
EP_TYPE_BULK,
MSC_Machine.MSC_BulkInEpSize);
} else {
pphost->user_callbk->huser_devunsupported();
}
return HSTATUS_OK ;
}
/**
* @brief deinitialize interface of msc class by freeing host channels
* @param [in] pdev device instance
* @retval None
*/
void usb_host_msc_itfdeinit(usb_core_instance *pdev)
{
if (MSC_Machine.hc_num_out != 0U) {
usb_hchstop(&pdev->regs, MSC_Machine.hc_num_out);
(void)usb_host_freech(pdev, MSC_Machine.hc_num_out);
MSC_Machine.hc_num_out = 0U;
}
if (MSC_Machine.hc_num_in != 0U) {
usb_hchstop(&pdev->regs, MSC_Machine.hc_num_in);
(void)usb_host_freech(pdev, MSC_Machine.hc_num_in);
MSC_Machine.hc_num_in = 0U;
}
}
/**
* @brief initialize the msc state machine
* @param [in] pdev device instance
* @param [in] phost host state set
* @retval status defined by HOST_STATUS
*/
HOST_STATUS usb_host_msc_classreq(usb_core_instance *pdev, void *phost)
{
USBH_MSC_BOTXferParam.MSCState = HOST_MSC_BOT_INIT_STATE;
return HSTATUS_OK;
}
/**
* @brief process the msc state machine
* @param [in] pdev device instance
* @param [in] phost host state set
* @retval status defined by HOST_STATUS
*/
HOST_STATUS usb_host_msc_process(usb_core_instance *pdev, void *phost)
{
USBH_HOST *pphost = phost;
HOST_STATUS status = HSTATUS_BUSY;
USB_HOST_MSC_STATUS mscStatus;
uint8_t appliStatus;
static uint8_t maxLunExceed = FALSE;
if (host_driver_ifdevconnected(pdev) != 0UL) {
switch (USBH_MSC_BOTXferParam.MSCState) {
case HOST_MSC_BOT_INIT_STATE:
usb_host_msc_init(pdev);
USBH_MSC_BOTXferParam.MSCState = HOST_MSC_BOT_RESET;
break;
case HOST_MSC_BOT_RESET:
/* issue a request to reset the bot. */
status = usb_host_msc_bot_reset(pdev, phost);
if (status == HSTATUS_OK) {
USBH_MSC_BOTXferParam.MSCState = HOST_MSC_GET_MAX_LUN;
}
if (status == HSTATUS_UNSUPPORTED) {
/* if the request fails, it needs to move to next state and should save the next state as backup */
USBH_MSC_BOTXferParam.MSCStateBkp = HOST_MSC_GET_MAX_LUN;
/* a clear feature should be issued if the request fails. */
USBH_MSC_BOTXferParam.MSCState = HOST_MSC_CTRL_ERROR_STATE;
}
break;
case HOST_MSC_GET_MAX_LUN:
/* issue a request to get the max logical unit(MAXLUN). */
status = usb_host_msc_maxlun_get(pdev, phost);
if (status == HSTATUS_OK) {
MSC_Machine.maxLun = *(MSC_Machine.buff) ;
if ((MSC_Machine.maxLun > 0U) && (maxLunExceed == FALSE)) {
maxLunExceed = TRUE;
pphost->user_callbk->huser_devunsupported();
break;
}
USBH_MSC_BOTXferParam.MSCState = HOST_MSC_TEST_UNIT_READY;
}
if (status == HSTATUS_UNSUPPORTED) {
/* if the request fails, it needs to move to next state and should save the next state as backup */
USBH_MSC_BOTXferParam.MSCStateBkp = HOST_MSC_TEST_UNIT_READY;
/* a clear feature should be issued if the request fails. */
USBH_MSC_BOTXferParam.MSCState = HOST_MSC_CTRL_ERROR_STATE;
}
break;
case HOST_MSC_CTRL_ERROR_STATE:
/* issue a request to clear feature */
status = usb_host_clrfeature(pdev,
phost,
0x00U,
pphost->ctrlparam.hc_num_out);
if (status == HSTATUS_OK) {
/* If GetMaxLun Request not support, assume Single LUN configuration */
MSC_Machine.maxLun = 0U;
USBH_MSC_BOTXferParam.MSCState = USBH_MSC_BOTXferParam.MSCStateBkp;
}
break;
case HOST_MSC_TEST_UNIT_READY:
/* issue the request Test Unit Ready[0] of SCSI command */
mscStatus = usb_host_msc_TestUnitReady(pdev);
if (mscStatus == USB_HOST_MSC_OK) {
USBH_MSC_BOTXferParam.MSCState = HOST_MSC_READ_CAPACITY10;
MSCErrorCount = 0U;
status = HSTATUS_OK;
} else {
usb_host_msc_error_process(mscStatus);
}
break;
case HOST_MSC_READ_CAPACITY10:
/* issue the request Read Capacity[0] of SCSI command. */
mscStatus = usb_host_msc_ReadCapacity10(pdev);
if (mscStatus == USB_HOST_MSC_OK) {
USBH_MSC_BOTXferParam.MSCState = HOST_MSC_MODE_SENSE6;
MSCErrorCount = 0U;
status = HSTATUS_OK;
} else {
usb_host_msc_error_process(mscStatus);
}
break;
case HOST_MSC_MODE_SENSE6:
/* issue the request ModeSense6 of SCSI command for detecting whelth the deviec is write-protected. */
mscStatus = usb_host_msc_ModeSense6(pdev);
if (mscStatus == USB_HOST_MSC_OK) {
USBH_MSC_BOTXferParam.MSCState = HOST_MSC_DEFAULT_APPLI_STATE;
MSCErrorCount = 0U;
status = HSTATUS_OK;
} else {
usb_host_msc_error_process(mscStatus);
}
break;
case HOST_MSC_REQUEST_SENSE:
/* issue the request RequestSense of SCSI command for retreiving error code. */
mscStatus = usb_host_msc_RequestSense(pdev);
if (mscStatus == USB_HOST_MSC_OK) {
USBH_MSC_BOTXferParam.MSCState = USBH_MSC_BOTXferParam.MSCStateBkp;
status = HSTATUS_OK;
} else {
usb_host_msc_error_process(mscStatus);
}
break;
case HOST_MSC_BOT_USB_TRANSFERS:
/* handle the BOT state machine. */
usb_host_msc_botxferprocess(pdev, phost);
break;
case HOST_MSC_DEFAULT_APPLI_STATE:
/* handle the user callback for the msc application. */
appliStatus = pphost->user_callbk->huser_application();
if (appliStatus == 0U) {
USBH_MSC_BOTXferParam.MSCState = HOST_MSC_DEFAULT_APPLI_STATE;
} else if (appliStatus == 1U) {
/* deinit requested from the application layer. */
status = HSTATUS_APP_DEINIT;
} else {
;
}
break;
case HOST_MSC_UNRECOVERED_STATE:
status = HSTATUS_UNRECOVERED_ERROR;
break;
default:
break;
}
}
return status;
}
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/*******************************************************************************
* EOF (not truncated)
******************************************************************************/

Some files were not shown because too many files have changed in this diff Show More