support wifi chip esp8266 based on uart2

This commit is contained in:
wlyu 2022-09-13 17:08:44 +08:00
parent 234c2b14fa
commit 9b47a30c09
6 changed files with 726 additions and 5 deletions

View File

@ -140,7 +140,7 @@ menuconfig BSP_USING_CAN
default n default n
menuconfig BSP_USING_ESP8266 menuconfig BSP_USING_ESP8266
depends on U16550_UART3 depends on U16550_UART2
bool "Using ESP8266 device" bool "Using ESP8266 device"
default n default n

View File

@ -58,4 +58,8 @@ ifeq ($(CONFIG_BSP_USING_CAN),y)
CSRCS += k210_can.c can_demo.c CSRCS += k210_can.c can_demo.c
endif endif
ifeq ($(CONFIG_BSP_USING_ESP8266),y)
CSRCS += k210_esp8266.c esp8266_demo.c
endif
include $(TOPDIR)/boards/Board.mk include $(TOPDIR)/boards/Board.mk

View File

@ -0,0 +1,118 @@
/*
* Copyright (c) 2022 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 esp8266_demo.c
* @brief xidatong-riscv64 esp8266_demo.c
* @version 1.0
* @author AIIT XUOS Lab
* @date 2022.08.22
*/
/****************************************************************************
* Included Files
****************************************************************************/
#include "k210_esp8266.h"
#include <sys/ioctl.h>
#include "time.h"
#define ec_print printf
#define ESP8266_DEMO_TIMEOUT 10
// first: receive \n\rRDY\n\r
// second: AT -> OK
static int esp8266_read_with_time(int fd, char *buffer, int seconds)
{
int read_size = 0;
time_t cur_time = time(NULL);
time_t last_time = cur_time;
while(cur_time < last_time + seconds)
{
read_size = read(fd, buffer, 256);
if(read_size < 0)
{
ec_print("esp8266 read failed %d\n", read_size);
return -ETIME;
}
else if(read_size)
{
ec_print("esp8266 read size %d ok!\n", read_size);
break;
}
cur_time = time(NULL);
}
return read_size;
}
int esp8266_check_demo(int fd, char *send_str, char *recv_str)
{
int ret;
char buf[ESP8266_RECV_BUF_SIZE] = {0};
if(send_str)
{
ret = write(fd, send_str, strlen(send_str));
if(ret < 0)
{
ec_print("esp8266 write failed %d\n", ret);
return ret;
}
ec_print("write %s ret = %d\n", send_str, ret);
}
ret = esp8266_read_with_time(fd, buf, ESP8266_DEMO_TIMEOUT);
if(ret < 0)
{
ec_print("esp8266 read failed %d\n", ret);
return ret;
}
ec_print("esp8266 read: %s!\n", buf);
if(strstr(buf, recv_str))
{
ec_print("esp8266 %s found!\n", recv_str);
}
return ret;
}
void Esp8266Demo(void)
{
int fd;
k210_gpiohs_set_value(FPIOA_ESP8266_EN, GPIO_PV_HIGH);
up_mdelay(100);
ec_print("start %s\n", __func__);
fd = open("/dev/esp8266", O_RDWR);
if(fd < 0)
{
ec_print("esp8266 open failed %d\n", fd);
return;
}
up_mdelay(2000);
esp8266_check_demo(fd, "AT\r\n", "OK");
close(fd);
ec_print("end %s\n", __func__);
}

View File

@ -0,0 +1,462 @@
/*
* Copyright (c) 2022 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 k210_esp8266.c
* @brief support to register esp8266 pointer and function
* @version 1.0
* @author AIIT XUOS Lab
* @date 2022-07-20
*/
#include <nuttx/fs/fs.h>
#include <nuttx/wqueue.h>
#include <sys/poll.h>
#include "ctype.h"
#include "k210_esp8266.h"
#define ec_print printf
/******************************************************************************/
struct esp8266_dev_s g_esp8266dev;
static char *esp8266_dev_name = "/dev/esp8266";
/******************************************************************************/
void esp8266_print_buf(int size, uint8_t *buf)
{
char ch[10] = {0};
char temp[256] = {0};
if(size >= 256)
size = 256;
for(int i = 0; i < size; i++)
{
if(buf[i] == '\r')
{
strcat(temp, "\\r");
}
else if(buf[i] == '\n')
{
strcat(temp, "\\n");
}
else if(isascii(buf[i]))
{
snprintf(ch, sizeof(ch), "%c", buf[i]);
strcat(temp, ch);
}
else
{
snprintf(ch, sizeof(ch), "%#x ", buf[i]);
strcat(temp, ch);
}
}
if(size)
ec_print("esp8266 read %d data: %s\n", size, temp);
}
int esp8266_read_buf(void *dev, int *size, uint8_t *buf)
{
uart_dev_t *uart_dev = (uart_dev_t *)dev;
int cur_size = uart_dev->recv.head - uart_dev->recv.tail;
*size = *size > cur_size ? cur_size : *size;
memcpy(buf, uart_dev->recv.buffer, *size);
uart_dev->recv.head = uart_dev->recv.tail;
esp8266_print_buf(*size, buf);
return *size;
}
/****************************************************************************
* Name: esp8266_data_work
*
* Description:
* thread task esp8266_data_work
*
****************************************************************************/
static FAR void esp8266_data_work(FAR void *arg)
{
struct esp8266_dev_s *esp8266_dev = (struct esp8266_dev_s *)arg;
uart_dev_t *uart_dev = esp8266_dev->uart_dev;
nxsem_wait(&esp8266_dev->waitsem);
esp8266_dev->recv_size = ESP8266_RECV_BUF_SIZE;
esp8266_read_buf(uart_dev, &esp8266_dev->recv_size, esp8266_dev->recv_buf);
work_queue(HPWORK, &esp8266_dev->irqwork, esp8266_data_work, esp8266_dev, ESP8266_INCREMENT);
// esp8266info("uart size %d ok!\n", esp8266_dev->recv_size);
}
static int esp8266_bringup(struct esp8266_dev_s *dev)
{
// struct esp8266_dev_s *esp8266_dev = &g_esp8266dev;
dev->uart_fd = open(dev->dev_name, O_RDWR);
esp8266info("open %s fd = %d\n", dev->dev_name, dev->uart_fd);
work_queue(HPWORK, &dev->irqwork, esp8266_data_work, dev, ESP8266_INCREMENT);
return OK;
}
static int esp8266_write_config(struct esp8266_dev_s *dev)
{
return OK;
}
static int esp8266_shutdown(struct esp8266_dev_s *dev)
{
close(dev->uart_fd);
return OK;
}
static int esp8266_open(FAR struct file *filep)
{
FAR struct inode *inode;
FAR struct esp8266_dev_s *priv;
uint8_t ref_cnt;
int ret;
DEBUGASSERT(filep);
inode = filep->f_inode;
DEBUGASSERT(inode && inode->i_private);
priv = (FAR struct esp8266_dev_s *)inode->i_private;
/* Get exclusive access to the driver data structure */
ret = nxsem_wait(&priv->devsem);
if(ret < 0)
{
esp8266err("ERROR: nxsem_wait failed: %d\n", ret);
return ret;
}
/* Increment the reference count */
ref_cnt = priv->crefs + 1;
if(ref_cnt == 0)
{
/* More than 255 opens; uint8_t overflows to zero */
nxsem_post(&priv->devsem);
return -EMFILE;
}
/* When the reference increments to 1, this is the first open event
* on the driver.. and the time when we must initialize the driver.
*/
if(ref_cnt == 1)
{
ret = esp8266_bringup(priv);
if(ret < 0)
{
esp8266err("ERROR: esp8266_bringup failed: %d\n", ret);
nxsem_post(&priv->devsem);
return ret;
}
ret = esp8266_write_config(priv);
if(ret < 0)
{
esp8266err("ERROR: esp8266_write_config failed: %d\n", ret);
nxsem_post(&priv->devsem);
return ret;
}
}
/* Save the new open count on success */
priv->crefs = ref_cnt;
nxsem_post(&priv->devsem);
return ret;
}
/****************************************************************************
* Name: esp8266_close
****************************************************************************/
static int esp8266_close(FAR struct file *filep)
{
FAR struct inode *inode;
FAR struct esp8266_dev_s *priv;
int ret;
DEBUGASSERT(filep);
inode = filep->f_inode;
DEBUGASSERT(inode && inode->i_private);
priv = (FAR struct esp8266_dev_s *)inode->i_private;
/* Get exclusive access to the driver data structure */
ret = nxsem_wait(&priv->devsem);
if(ret < 0)
{
esp8266err("ERROR: nxsem_wait failed: %d\n", ret);
return ret;
}
/* Decrement the reference count unless it would decrement a negative
* value.
*/
if(priv->crefs >= 1)
{
priv->crefs--;
}
/* When the count decrements to zero, there are no further open references
* to the driver and it esp8266 be uninitialized.
*/
if(priv->crefs == 0)
{
esp8266_shutdown(priv);
}
nxsem_post(&priv->devsem);
return OK;
}
/****************************************************************************
* Name: esp8266_read
****************************************************************************/
static ssize_t esp8266_read(FAR struct file *filep, FAR char *buffer, size_t len)
{
FAR struct inode *inode;
FAR struct esp8266_dev_s *priv;
int ret, buf_size = len;
DEBUGASSERT(filep);
inode = filep->f_inode;
DEBUGASSERT(inode && inode->i_private);
priv = (FAR struct esp8266_dev_s *)inode->i_private;
ret = nxsem_wait(&priv->devsem);
if(ret < 0)
{
esp8266err("ERROR: nxsem_wait failed: %d\n", ret);
return ret;
}
buf_size = len > priv->recv_size ? priv->recv_size : len;
memcpy(buffer, priv->recv_buf, buf_size);
nxsem_post(&priv->devsem);
return ret;
}
/****************************************************************************
* Name: esp8266_write
****************************************************************************/
static ssize_t esp8266_write(FAR struct file *filep, FAR const char *buffer, size_t len)
{
FAR struct inode *inode;
FAR struct esp8266_dev_s *priv;
int ret;
DEBUGASSERT(filep);
inode = filep->f_inode;
DEBUGASSERT(inode && inode->i_private);
priv = (FAR struct esp8266_dev_s *)inode->i_private;
/* Get exclusive access to the driver data structure */
ret = nxsem_wait(&priv->devsem);
if(ret < 0)
{
esp8266err("ERROR: nxsem_wait failed: %d\n", ret);
return ret;
}
ret = write(priv->uart_fd, buffer, len);
esp8266info("write fd %d len %ld ret = %d\n", priv->uart_fd, len, ret);
nxsem_post(&priv->devsem);
return ret;
}
/****************************************************************************
* Name: esp8266_ioctl
****************************************************************************/
static int esp8266_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
{
FAR struct inode *inode;
FAR struct esp8266_dev_s *priv;
FAR uint32_t *ptr;
int ret;
DEBUGASSERT(filep);
inode = filep->f_inode;
DEBUGASSERT(inode && inode->i_private);
priv = (FAR struct esp8266_dev_s *)inode->i_private;
/* Get exclusive access to the driver data structure */
ret = nxsem_wait(&priv->devsem);
if(ret < 0)
{
esp8266err("ERROR: nxsem_wait failed: %d\n", ret);
return ret;
}
/* Process the IOCTL by command */
switch(cmd)
{
case ESP8266IOC_SETFREQUENCY: /* arg: Pointer to uint32_t frequency value */
ptr = (FAR uint32_t *)((uintptr_t)arg);
DEBUGASSERT(priv->config != NULL && ptr != NULL);
break;
default:
ret = -ENOTTY;
break;
}
nxsem_post(&priv->devsem);
return ret;
}
/****************************************************************************
* Name: esp8266_poll
****************************************************************************/
static int esp8266_poll(FAR struct file *filep, FAR struct pollfd *fds, bool setup)
{
FAR struct inode *inode;
FAR struct esp8266_dev_s *priv;
int ret;
esp8266info("setup: %d\n", (int)setup);
DEBUGASSERT(filep && fds);
inode = filep->f_inode;
DEBUGASSERT(inode && inode->i_private);
priv = (FAR struct esp8266_dev_s *)inode->i_private;
/* Are we setting up the poll? Or tearing it down? */
ret = nxsem_wait(&priv->devsem);
if(ret < 0)
{
esp8266err("ERROR: nxsem_wait failed: %d\n", ret);
return ret;
}
if(setup)
{
/* Ignore waits that do not include POLLIN */
if((fds->events & POLLIN) == 0)
{
esp8266err("ERROR: Missing POLLIN: revents: %08x\n", fds->revents);
nxsem_post(&priv->devsem);
return -EDEADLK;
}
esp8266_notify(priv->uart_dev);
}
else if(fds->priv)
{
/* This is a request to tear down the poll. */
struct pollfd **slot = (struct pollfd **)fds->priv;
DEBUGASSERT(slot != NULL);
/* Remove all memory of the poll setup */
*slot = NULL;
fds->priv = NULL;
}
nxsem_post(&priv->devsem);
return ret;
}
static const struct file_operations esp8266_fops =
{
esp8266_open, /* open */
esp8266_close, /* close */
esp8266_read, /* read */
esp8266_write, /* write */
NULL, /* seek */
esp8266_ioctl, /* ioctl */
esp8266_poll /* poll */
};
/****************************************************************************
* Name: esp8266_register
*
* Description:
* Register /dev/ext_uartN
*
****************************************************************************/
static int esp8266_register(FAR const char *devpath)
{
FAR struct esp8266_dev_s *priv = &g_esp8266dev;
int ret = 0;
nxsem_init(&priv->devsem, 0, 1);
nxsem_init(&priv->waitsem, 0, 0);
nxsem_set_protocol(&priv->waitsem, SEM_PRIO_NONE);
/* Register the driver */
ret = register_driver(devpath, &esp8266_fops, 0666, priv);
if(ret < 0)
{
kmm_free(priv);
}
return ret;
}
void esp8266_notify(uart_dev_t *dev)
{
if(dev == g_esp8266dev.uart_dev)
nxsem_post(&g_esp8266dev.waitsem);
}
/****************************************************************************
* Name: esp8266_init
*
* Description:
* Ch376 default initialization function
*
****************************************************************************/
void board_esp8266_initialize(void)
{
k210_fpioa_config(ESP8266_EN_PIN, ESP8266_FUNC_GPIO(FPIOA_ESP8266_EN));
k210_gpiohs_set_direction(FPIOA_ESP8266_EN, GPIO_DM_OUTPUT);
k210_gpiohs_set_value(FPIOA_ESP8266_EN, GPIO_PV_HIGH);
fpioa_set_function(ESP8266_RX_PIN, FPIOA_ESP8266_RX);
fpioa_set_function(ESP8266_TX_PIN, FPIOA_ESP8266_TX);
#if defined(CONFIG_U16550_UART2)
g_esp8266dev.dev_name = "/dev/uart2";
u16550_register(&g_esp8266dev.uart_dev, 2);
esp8266_register(esp8266_dev_name);
esp8266info("dev %p ok!\n", g_esp8266dev.uart_dev);
#endif
}

View File

@ -0,0 +1,137 @@
/*
* Copyright (c) 2022 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 k210_esp8266.h
* @brief define aiit-riscv64-board esp8266 function and struct
* @version 1.0
* @author AIIT XUOS Lab
* @date 2022-09-7
*/
#ifndef __K210_ESP8266_H_
#define __K210_ESP8266_H_
#include <nuttx/config.h>
#include <nuttx/kmalloc.h>
#include <nuttx/arch.h>
#include <nuttx/irq.h>
#include <nuttx/pthread.h>
#include <nuttx/semaphore.h>
#include <nuttx/wqueue.h>
#include <nuttx/wdog.h>
#include <nuttx/clock.h>
#include <nuttx/time.h>
#include <nuttx/fs/fs.h>
#include <nuttx/fs/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <sched.h>
#include <debug.h>
#include <assert.h>
#include <unistd.h>
#include <stdbool.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <arch/board/board.h>
#include "riscv_internal.h"
#include "k210_config.h"
#include "k210_fpioa.h"
#include "k210_gpiohs.h"
#include "xidatong-riscv64.h"
#include "nuttx/serial/serial.h"
#include "nuttx/serial/uart_16550.h"
/* Define CH438 PIN NUM */
#define ESP8266_RX_PIN 6
#define ESP8266_TX_PIN 7
#define ESP8266_EN_PIN 8
/* Define ch438 FPIOA NUMBER */
#define FPIOA_ESP8266_RX 66
#define FPIOA_ESP8266_TX 67
#define FPIOA_ESP8266_EN 4
#define ESP8266_FUNC_GPIO(n) ((K210_IO_FUNC_GPIOHS0 + n) | K210_IOFLAG_GPIOHS)
#define ESP8266IOC_SETFREQUENCY _WLIOC(0x0001) /* arg: Pointer to uint32_t frequency value */
#define ESP8266IOC_GETFREQUENCY _WLIOC(0x0002) /* arg: Pointer to uint32_t frequency value */
/* esp8266 debug */
#ifdef CONFIG_DEBUG_ESP8266_ERROR
# define esp8266err _err
#else
# define esp8266err _none
#endif
#ifdef CONFIG_DEBUG_ESP8266_WARN
# define esp8266warn _warn
#else
# define esp8266warn _none
#endif
#ifdef CONFIG_DEBUG_ESP8266_INFO
# define esp8266info _info
#else
# define esp8266info _none
#endif
#define ESP8266_RECV_BUF_SIZE 256
#define ESP8266_INCREMENT MSEC2TICK(33)
struct esp8266_config_s
{
int (*attach)(FAR const struct esp8266_config_s *config, xcpt_t isr,
FAR void *arg);
void (*enable)(FAR const struct esp8266_config_s *config, bool enable);
void (*clear)(FAR const struct esp8266_config_s *config);
void (*wakeup)(FAR const struct esp8266_config_s *config);
void (*nreset)(FAR const struct esp8266_config_s *config, bool state);
};
struct esp8266_dev_s
{
uint8_t crefs; /* Number of times the device
* has been opened */
uint8_t nwaiters; /* Number of threads waiting for
* data */
sem_t devsem; /* Manages exclusive access to
* this structure */
sem_t waitsem; /* Used to wait for the
* availability of data */
FAR const struct esp8266_config_s *config; /* Board configuration data */
struct work_s irqwork; /* Supports the interrupt
* handling "bottom half" */
char *dev_name;
int uart_fd;
uart_dev_t *uart_dev;
int recv_size;
uint8_t recv_buf[ESP8266_RECV_BUF_SIZE];
};
void esp8266_notify(uart_dev_t *dev);
void board_esp8266_initialize(void);
#endif

View File

@ -47,11 +47,11 @@ int k210_fpioa_get_io_by_function(uint8_t function)
{ {
int index = 0; int index = 0;
uint32_t RegValue = 0x0000; uint32_t RegValue = 0x0000;
uint32_t *fpioa = (uint32_t *)K210_FPIOA_BASE; uint32_t *fpioa_base = (uint32_t *)K210_FPIOA_BASE;
for (index = 0; index < K210_IO_NUMBER; index++) for (index = 0; index < K210_IO_NUMBER; index++)
{ {
RegValue = getreg32(&fpioa[index]); RegValue = getreg32(&fpioa_base[index]);
if ((RegValue & 0xFF) == function) if ((RegValue & 0xFF) == function)
return index; return index;
} }
@ -61,7 +61,7 @@ int k210_fpioa_get_io_by_function(uint8_t function)
void k210_fpioa_config(uint32_t io, uint32_t ioflags) void k210_fpioa_config(uint32_t io, uint32_t ioflags)
{ {
uint32_t *fpioa = (uint32_t *)K210_FPIOA_BASE; uint32_t *fpioa_base = (uint32_t *)K210_FPIOA_BASE;
DEBUGASSERT(io < K210_IO_NUMBER); DEBUGASSERT(io < K210_IO_NUMBER);
putreg32(ioflags, &fpioa[io]); putreg32(ioflags, &fpioa_base[io]);
} }