NuttX的应用记录 1

由于种种原因,需要一个大批量烧录8266模块的烧录器,最小单位为一整张PCBA拼版,4x4=16拼版。
我能想到的几种解决方法。

  1. 用电脑烧录
    电脑后面就6个USB母口,显然不现实,就算是我使用了4片CP2108使串口数量达到16,面对16个烧录窗口,我觉得我要崩溃了。
  2. 用烧录机器烧录
    使用烧录机烧录FLASH,再贴片后,即可达到效果,但是,如果人家就要200片呢,哪个贴片厂愿意接200片的单。。。而且也不划算。
  3. 离线式烧录机器
    参考FLASH烧录机,可以做一台离线式烧录机器。能拥有16个串口的,我想也就只有万能的FPGA了(笑~)。但是这个东东我用的也不是很熟练,让我来做这个东西的话,不知道得花掉我多少时间。退求其次,使用一些(比如32)小芯片提供串口。可供参考的芯片有:
    1. STM32
    2. STM32
    3. STM32

那还等什么,就它了。
计划为使用17片、9片或者5片32共同提供16个串口出来。其中,1片32作为主控,控制其他32一起烧录。中间通过什么总线来控制就可以了。主控32可以连在电脑上,从电脑上下载程序到一片FLASH中,这个FLASH搞得大一点,64M bit吧。主控命令其他32依次“下载”固件到它们自己的FLASH上。即可完成同步。整体框架就这样计划了。

2018.10.11
要搞明白烧录过程是如何进行的,就需要拿出一台什么啊,逻辑分析仪。运行esptool read_mac对着串口就是一顿抓。
逻辑分析仪

使用自带解析器解析一下,电脑端全程都是在用115200来通讯的。观察可以得出,发送的东西是以一个特定字符作为开和结尾的:“0xC0”。分开导出两个波形。将每个包单独放置。对着esptool.py脚本看,可以得出一个通讯顺序,同步后加上读取一些寄存器。通过寄存器读到的数据就可以得到MAC地址。

包分析

可以看到,同一个寄存器来来回回,反反复复读了好几次啊。这里批评一下。
下面先来写程序完成一次读取MAC码。显然,我要使用NuttX。

menuconfig中打开一个能接线在8266串口上的串口。我用的是l475,那就是uart4了。

> System Type > STM32L4 Peripheral Support > [*] UART4

可以在终端中看到两个串口设备了。

nsh>cd dev
nsh>ls
/dev:
 console
 null
 ttyS0
 ttyS1
 zero
nsh>

想要烧录8266,需要将8266的IO0拉低并重启。使其进入下载模式。那么还需要两个GPIO。一个控制8266的供电,一个控制IO0。为什么不控制RST或者EN脚呢,因为我想到,假如有模块贴NG或者短路了,那么可以把它关掉。避免其影响到整版的烧录。最后通过板载的指示灯来提示那个NG的模块,方便作业人员给它贴个NG贴。

好了,继续,既然是在NuttX下,那么我就不用寄存器级的代码来控制IO了,所以,将GPIO挂载到dev下是下一步任务。
在驱动中开启GPIO的驱动。

> Device Drivers > IO Expander/GPIO Support > [*] GPIO driver

下面去找代码。不难找,就在

nuttx\drivers\ioexpander\gpio.c:338:
int gpio_pin_register(FAR struct gpio_dev_s *dev, int minor)

全局搜索,

nuttx\configs\stm32f103-minimum\src\stm32_gpio.c

照抄这个文件就行了。
不一样的地方首先就在输入端和输出端上。这里只需要2个输出口就可以了。所以。

#if BOARD_NGPIOIN > 0
/* This array maps the GPIO pins used as INPUT */

static const uint32_t g_gpioinputs[BOARD_NGPIOIN] =
{
};

static struct stm32gpio_dev_s g_gpin[BOARD_NGPIOIN];
#endif

#if BOARD_NGPIOOUT
/* This array maps the GPIO pins used as OUTPUT */

static const uint32_t g_gpiooutputs[BOARD_NGPIOOUT] =
{
  GPIO_OUT0,
  GPIO_OUT1
};

static struct stm32gpio_dev_s g_gpout[BOARD_NGPIOOUT];
#endif

#if BOARD_NGPIOINT > 0
/* This array maps the GPIO pins used as INTERRUPT INPUTS */

static const uint32_t g_gpiointinputs[BOARD_NGPIOINT] =
{
};

static struct stm32gpint_dev_s g_gpint[BOARD_NGPIOINT];
#endif

接下来在头文件中加入一段这样的东东

/* Arduino GPIO
 * ARD.A0	PC5
 * ARD.A1	PC4
 * ARD.A2	PC3
 * ARD.A3	PC2
 * ARD.A4	PC1
 * ARD.A5	PC0
 *
 * ARD.D0	PA1     ----UART4----
 * ARD.D1	PA0     ----UART4----
 * ARD.D2	PD14    ---- gpio0 ---->
 * ARD.D3	PB0     ---- gpio1 ---->
 * ARD.D4	PA3
 * ARD.D5	PB4
 * ARD.D6	PB1
 * ARD.D7	PA4
 * ARD.D8	PB2
 * ARD.D9	PA15
 * ARD.D10	PA2
 * ARD.D11	PA7
 * ARD.D12	PA6
 * ARD.D13	PA5
 * ARD.D14	PB9
 * ARD.D15	PB8
 */

#define BOARD_NGPIOOUT  2
#define GPIO_OUT0       (GPIO_OUTPUT | GPIO_PUSHPULL | GPIO_SPEED_50MHz |\
                         GPIO_OUTPUT_CLEAR | GPIO_PORTD | GPIO_PIN14)
#define GPIO_OUT1       (GPIO_OUTPUT | GPIO_PUSHPULL | GPIO_SPEED_50MHz |\
                         GPIO_OUTPUT_CLEAR | GPIO_PORTB | GPIO_PIN0)

整个stm32_gpio.c内容就很好写了。

/****************************************************************************
 * Included Files
 ****************************************************************************/

#include <nuttx/config.h>
#include <nuttx/timers/timer.h>

#include <debug.h>

#include <nuttx/ioexpander/gpio.h>

#include "stm32l4_gpio.h"

#include "b-l475e-iot01a.h"

#if defined(CONFIG_DEV_GPIO) && !defined(CONFIG_GPIO_LOWER_HALF)

/****************************************************************************
 * Private Types
 ****************************************************************************/

struct stm32gpio_dev_s
{
  struct gpio_dev_s gpio;
  uint8_t id;
};

struct stm32gpint_dev_s
{
  struct stm32gpio_dev_s stm32gpio;
  pin_interrupt_t callback;
};

/****************************************************************************
 * Private Function Prototypes
 ****************************************************************************/

#if BOARD_NGPIOIN > 0
static int gpin_read(FAR struct gpio_dev_s *dev, FAR bool *value);
#endif
#if BOARD_NGPIOOUT
static int gpout_read(FAR struct gpio_dev_s *dev, FAR bool *value);
static int gpout_write(FAR struct gpio_dev_s *dev, bool value);
#endif
#if BOARD_NGPIOINT > 0
static int gpint_read(FAR struct gpio_dev_s *dev, FAR bool *value);
static int gpint_attach(FAR struct gpio_dev_s *dev,
                        pin_interrupt_t callback);
static int gpint_enable(FAR struct gpio_dev_s *dev, bool enable);
#endif

/****************************************************************************
 * Private Data
 ****************************************************************************/

#if BOARD_NGPIOIN > 0
static const struct gpio_operations_s gpin_ops =
{
  .go_read   = gpin_read,
  .go_write  = NULL,
  .go_attach = NULL,
  .go_enable = NULL,
};
#endif

#if BOARD_NGPIOOUT
static const struct gpio_operations_s gpout_ops =
{
  .go_read   = gpout_read,
  .go_write  = gpout_write,
  .go_attach = NULL,
  .go_enable = NULL,
};
#endif

#if BOARD_NGPIOINT > 0
static const struct gpio_operations_s gpint_ops =
{
  .go_read   = gpint_read,
  .go_write  = NULL,
  .go_attach = gpint_attach,
  .go_enable = gpint_enable,
};
#endif

#if BOARD_NGPIOIN > 0
/* This array maps the GPIO pins used as INPUT */

static const uint32_t g_gpioinputs[BOARD_NGPIOIN] =
{
};

static struct stm32gpio_dev_s g_gpin[BOARD_NGPIOIN];
#endif

#if BOARD_NGPIOOUT
/* This array maps the GPIO pins used as OUTPUT */

static const uint32_t g_gpiooutputs[BOARD_NGPIOOUT] =
{
  GPIO_OUT0,
  GPIO_OUT1
};

static struct stm32gpio_dev_s g_gpout[BOARD_NGPIOOUT];
#endif

#if BOARD_NGPIOINT > 0
/* This array maps the GPIO pins used as INTERRUPT INPUTS */

static const uint32_t g_gpiointinputs[BOARD_NGPIOINT] =
{
};

static struct stm32gpint_dev_s g_gpint[BOARD_NGPIOINT];
#endif

/****************************************************************************
 * Private Functions
 ****************************************************************************/
#if BOARD_NGPIOINT > 0
static int stm32gpio_interrupt(int irq, void *context, void *arg)
{
  FAR struct stm32gpint_dev_s *stm32gpint = (FAR struct stm32gpint_dev_s *)arg;

  DEBUGASSERT(stm32gpint != NULL && stm32gpint->callback != NULL);
  gpioinfo("Interrupt! callback=%p\n", stm32gpint->callback);

  stm32gpint->callback(&stm32gpint->stm32gpio.gpio, tm32gpint->stm32gpio.id);
  return OK;
}
#endif

#if BOARD_NGPIOIN > 0
static int gpin_read(FAR struct gpio_dev_s *dev, FAR bool *value)
{
  FAR struct stm32gpio_dev_s *stm32gpio = (FAR struct stm32gpio_dev_s *)dev;

  DEBUGASSERT(stm32gpio != NULL && value != NULL);
  DEBUGASSERT(stm32gpio->id < BOARD_NGPIOIN);
  gpioinfo("Reading...\n");

  *value = stm32l4_gpioread(g_gpioinputs[stm32gpio->id]);
  return OK;
}
#endif

#if BOARD_NGPIOOUT
static int gpout_read(FAR struct gpio_dev_s *dev, FAR bool *value)
{
  FAR struct stm32gpio_dev_s *stm32gpio = (FAR struct stm32gpio_dev_s *)dev;

  DEBUGASSERT(stm32gpio != NULL && value != NULL);
  DEBUGASSERT(stm32gpio->id < BOARD_NGPIOOUT);
  gpioinfo("Reading...\n");

  *value = stm32l4_gpioread(g_gpiooutputs[stm32gpio->id]);
  return OK;
}

static int gpout_write(FAR struct gpio_dev_s *dev, bool value)
{
  FAR struct stm32gpio_dev_s *stm32gpio = (FAR struct stm32gpio_dev_s *)dev;

  DEBUGASSERT(stm32gpio != NULL);
  DEBUGASSERT(stm32gpio->id < BOARD_NGPIOOUT);
  gpioinfo("Writing %d\n", (int)value);

  stm32l4_gpiowrite(g_gpiooutputs[stm32gpio->id], value);
  return OK;
}
#endif

#if BOARD_NGPIOINT > 0
static int gpint_read(FAR struct gpio_dev_s *dev, FAR bool *value)
{
  FAR struct stm32gpint_dev_s *stm32gpint = (FAR struct stm32gpint_dev_s *)dev;

  DEBUGASSERT(stm32gpint != NULL && value != NULL);
  DEBUGASSERT(stm32gpint->stm32gpio && stm32gpint->stm32gpio.id < BOARD_NGPIOINT);
  gpioinfo("Reading int pin...\n");

  *value = stm32l4_gpioread(g_gpiointinputs[stm32gpint->stm32gpio.id]);
  return OK;
}

static int gpint_attach(FAR struct gpio_dev_s *dev,
                        pin_interrupt_t callback)
{
  FAR struct stm32gpint_dev_s *stm32gpint = (FAR struct stm32gpint_dev_s *)dev;

  gpioinfo("Attaching the callback\n");

  /* Make sure the interrupt is disabled */

  (void)stm32l4_gpiosetevent(g_gpiointinputs[stm32gpint->stm32gpio.id], false,
                           false, false, NULL, NULL);

  gpioinfo("Attach %p\n", callback);
  stm32gpint->callback = callback;
  return OK;
}

static int gpint_enable(FAR struct gpio_dev_s *dev, bool enable)
{
  FAR struct stm32gpint_dev_s *stm32gpint = (FAR struct stm32gpint_dev_s *)dev;

  if (enable)
    {
      if (stm32gpint->callback != NULL)
        {
          gpioinfo("Enabling the interrupt\n");

          /* Configure the interrupt for rising edge */

          (void)stm32l4_gpiosetevent(g_gpiointinputs[stm32gpint->stm32gpio.id],
                                   true, false, false, stm32gpio_interrupt,
                                   &g_gpint[stm32gpint->stm32gpio.id]);
        }
    }
  else
    {
      gpioinfo("Disable the interrupt\n");

      (void)stm32l4_gpiosetevent(g_gpiointinputs[stm32gpint->stm32gpio.id],
                               false, false, false, NULL, NULL);
    }

  return OK;
}
#endif

/****************************************************************************
 * Public Functions
 ****************************************************************************/

/****************************************************************************
 * Name: stm32_gpio_initialize
 *
 * Description:
 *   Initialize GPIO drivers for use with /apps/examples/gpio
 *
 ****************************************************************************/

int stm32l4_gpio_initialize(void)
{
  int pincount = 0;
  int i;

#if BOARD_NGPIOIN > 0
  for (i = 0; i < BOARD_NGPIOIN; i++)
    {
      /* Setup and register the GPIO pin */

      g_gpin[i].gpio.gp_pintype = GPIO_INPUT_PIN;
      g_gpin[i].gpio.gp_ops     = &gpin_ops;
      g_gpin[i].id              = i;
      (void)gpio_pin_register(&g_gpin[i].gpio, pincount);

      /* Configure the pin that will be used as input */

      stm32l4_configgpio(g_gpioinputs[i]);

      pincount++;
    }
#endif

#if BOARD_NGPIOOUT > 0
  for (i = 0; i < BOARD_NGPIOOUT; i++)
    {
      /* Setup and register the GPIO pin */

      g_gpout[i].gpio.gp_pintype = GPIO_OUTPUT_PIN;
      g_gpout[i].gpio.gp_ops     = &gpout_ops;
      g_gpout[i].id              = i;
      (void)gpio_pin_register(&g_gpout[i].gpio, pincount);

      /* Configure the pin that will be used as output */

      stm32l4_gpiowrite(g_gpiooutputs[i], 0);
      stm32l4_configgpio(g_gpiooutputs[i]);

      pincount++;
    }
#endif

#if BOARD_NGPIOINT > 0
  for (i = 0; i < BOARD_NGPIOINT; i++)
    {
      /* Setup and register the GPIO pin */

      g_gpint[i].stm32gpio.gpio.gp_pintype = GPIO_INTERRUPT_PIN;
      g_gpint[i].stm32gpio.gpio.gp_ops     = &gpint_ops;
      g_gpint[i].stm32gpio.id              = i;
      (void)gpio_pin_register(&g_gpint[i].stm32gpio.gpio, pincount);

      /* Configure the pin that will be used as interrupt input */

      stm32l4_configgpio(g_gpiointinputs[i]);

      pincount++;
    }
#endif

  return 0;
}

#endif /* CONFIG_DEV_GPIO && !CONFIG_GPIO_LOWER_HALF */

补齐其他文件中缺失的东西。编译运行。

NuttShell (NSH)
nsh>cd /dev
nsh>ls
/dev:
 console
 gpout0
 gpout1
 null
 ttyS0
 ttyS1
 zero
nsh>

两个gpio出现了。因为是输出脚,所以叫做gpout。问题不大。明天再写吧。

2018.10.13

启用例子gpio,看到有一个叫cu的小程序可以控制串口。也一并启用了。

> Application Configuration > Examples > [*] GPIO driver example
> Application Configuration > System Libraries and NSH Add-Ons > [*] CU minimal serial terminal

编译失败,提示tcflush()函数没有定义。查找文件后发现头文件和源文件均没有出错,那问题在哪。

没有定义,那说明定义部分没有被编译。查看Make.defs文件:

ifneq ($(CONFIG_NFILE_DESCRIPTORS),0)
ifeq ($(CONFIG_SERIAL_TERMIOS),y)

# Add the termios C files to the build

CSRCS += lib_cfgetspeed.c lib_cfsetspeed.c lib_cfmakeraw.c lib_isatty.c lib_tcflush.c
CSRCS += lib_tcflow.c lib_tcgetattr.c lib_tcsetattr.c

# Add the termios directory to the build

DEPPATH += --dep-path termios
VPATH += termios

endif
endif

这里有两个定义 CONFIG_NFILE_DESCRIPTORSCONFIG_SERIAL_TERMIOS。第一个已经定义了,第二个位置在:

> Device Drivers > Serial Driver Support > [*]   Serial TERMIOS support

再编译还是不通过。提示:

CC:  chip/stm32l4_serial.c
chip/stm32l4_serial.c:526:20: error: 'GPIO_USART2_TX' undeclared here (not in a function)
   .tx_gpio       = GPIO_USART2_TX,
                    ^~~~~~~~~~~~~~
chip/stm32l4_serial.c:527:20: error: 'GPIO_USART2_RX' undeclared here (not in a function)
   .rx_gpio       = GPIO_USART2_RX,
                    ^~~~~~~~~~~~~~
Makefile:190: recipe for target 'stm32l4_serial.o' failed

这个是说这两个io口没有定义。
arch\arm\src\chip\chip\stm32l4x5xx_pinmap.h中寻找我要的那开两个io PA0 和PA1

将此定义添加在板子的头文件中。

#define GPIO_UART4_TX   GPIO_UART4_TX_1
#define GPIO_UART4_RX   GPIO_UART4_RX_1

再编译就通过了。

使用gpio来控制io口。

nsh>gpio -h
USAGE: gpio [-w <signo>] [-o <value>] <driver-path>
       gpio -h
Where:
        <driver-path>: The full path to the GPIO pin driver.
        -w <signo>: Wait for an signal if this is an interrupt pin.
        -o <value>:  Write this value (0 or 1) if this is an output pin.
        -h: Print this usage information and exit.
nsh>gpio -o 1 /dev/gpout0
Driver: /dev/gpout0
  Output pin:    Value=1
  Writing:       Value=1
  Verify:        Value=1
nsh>gpio -o 0 /dev/gpout0
Driver: /dev/gpout0
  Output pin:    Value=1
  Writing:       Value=0
  Verify:        Value=0
nsh>

可以控制。下一个。

使用cu来和8266通讯

NuttShell (NSH)
nsh>cu -s "74880" /dev/ttyS1

 ets Jan  8 2013,rst cause:2, boot mode:(3,6)

load 0x40100000, len 2592, room 16
tail 0
chksum 0xf3
load 0x3ffe8000, len 764, room 8
tail 4
chksum 0x92
load 0x3ffe82fc, len 676, room 4
tail 0
chksum 0x22
csum 0x22

2nd boot version : 1.7(5d6f877)
SPI Speed : 40MHz
SPI Mode : DOUT
SPI Flash Size & Map: 8Mbit(512KB+512KB)
jump to run user1 @ 1000

OS SDK ver: 2.0-dev(52b3b54) compiled @ Mar 22 2018 18:37:24
phy ver: 1055_1, pp ver: 10.7

rf cal sector: 251
tcpip_task_hdl : 40107bc8, prio:10,stack:512
idle_task_hdl : 40107c78,prio:0, stack:384
tim_task_hdl : 40107dc0, prio:2,stack:512
p)D豖? ?
         `驮

注意,这里的-s 的附加参数需要用引号括起来。不然不会生效。


2018.10.17
昨天一天只顾着写了,没有做记录。
大概记录一下都干了啥。

因为要用两个串口同时通讯,所以先写了一个任务。由这个新任务来负责一个串口的。只要再运行这个任务,换一个参数就可以控制两个串口了。

每个任务单独运行两个读取和写入,读取就单独是都去就可以了,观察时序,发现并不存在双工的情况,所以读取和接收两个pthread可以上个锁。同时只运行一个。

使用最简单的

sem_init(&sem, 0, 0);
...
sem_post(&sem);
...
sem_post(&sem);

剩下的参考Linux下的串口设置之类的就可以了。

更具逻辑分析仪的结果。读取MAC与8266的通讯过程是:

  1. 同步
  2. 同步
  3. 读取寄存器

看起来很简单,首先吧这个同步信号全部导入进来。

const uint8_t SYNC_PACK[46] =
{
  0xC0, 0x00, 0x08, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
  0x07, 0x12, 0x20, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
  0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
  0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
  0x55, 0x55, 0x55, 0x55, 0x55, 0xC0
};

在8266启动后,发送两次SYNC_PACK就可以了,时间间隔我设置为50ms,这个用usleep就可以了。
接下来8266会返回8次不知道是啥意义的数据。我暂且定义为SYNC_ACK吧。

const uint8_t SYNC_ACK[12] =
{
  0xC0, 0x01, 0x08, 0x02, 0x00, 0x07, 0x07, 0x12, 0x20, 0x00,
  0x00, 0xC0
};

接下来,由电脑端发送了一些读取寄存器的命令。这些地址分别为:

ESP_OTP_MAC0           0x3FF00050
ESP_OTP_MAC1           0x3FF00054
ESP_OTP_MAC2           0x3FF00058
ESP_OTP_MAC3           0x3FF0005C

干脆这些读取寄存器的包也存起来。

const uint8_t READ_ESP_OTP_MAC[4][14] =
{
  {
    0xC0, 0x00, 0x0A, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50,
	0x00, 0xF0, 0x3F, 0xC0
  },
  {
    0xC0, 0x00, 0x0A, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54,
    0x00, 0xF0, 0x3F, 0xC0
  },
  {
    0xC0, 0x00, 0x0A, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58,
    0x00, 0xF0, 0x3F, 0xC0
  },
  {
    0xC0, 0x00, 0x0A, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5C,
    0x00, 0xF0, 0x3F, 0xC0
  }
};

将这些发送出去就能得到对应的寄存器值了。

MAC的获取方法,参照esptool内的写法:

if (mac3 != 0):
    oui = ((mac3 >> 16) & 0xff, (mac3 >> 8) & 0xff, mac3 & 0xff)
elif ((mac1 >> 16) & 0xff) == 0:
    oui = (0x18, 0xfe, 0x34)
elif ((mac1 >> 16) & 0xff) == 1:
    oui = (0xac, 0xd0, 0x74)
else:
    raise FatalError("Unknown OUI")
return oui + ((mac1 >> 8) & 0xff, mac1 & 0xff, (mac0 >> 24) & 0xff)

基本上照抄就行了:

if (ESP_OTP_MAC3 != 0)
  {
    MAC[0] = (ESP_OTP_MAC3 >> 16) & 0xFF;
    MAC[1] = (ESP_OTP_MAC3 >>  8) & 0xFF;
    MAC[2] = (ESP_OTP_MAC3 >>  0) & 0xFF;
  }
  else if (((ESP_OTP_MAC1 >> 16) & 0xFF) == 0)
  {
    MAC[0] = 0x18;
    MAC[1] = 0xFE;
    MAC[2] = 0x34;
  }
  else if (((ESP_OTP_MAC1 >> 16) & 0xFF) == 1)
  {
    MAC[0] = 0xAC;
    MAC[1] = 0xD0;
    MAC[2] = 0x74;
  }
  MAC[3] = (ESP_OTP_MAC1 >>  8) & 0xFF;
  MAC[4] = (ESP_OTP_MAC1 >>  0) & 0xFF;
  MAC[5] = (ESP_OTP_MAC0 >> 24) & 0xFF;

  sprintf(MAC_STR, "%02X%02X%02X%02X%02X%02X",
      MAC[0],MAC[1],MAC[2],MAC[3],MAC[4],MAC[5]);

两个pthread的代码如下。
首先是发送线程,发送线程担当着重任。(是因为懒得再加进程控制逻辑。这些东西本来应该是放在上一个task中的,闲的时候再改吧)

static void *tx_pthread(FAR void *parameter) {
  int tx_fd = (int) ((intptr_t) parameter);
  int status;

SYNC:

  for (int var = 0; var < 3; ++var)
  {
    write(tx_fd, SYNC_PACK, (size_t) 46);
    if (var == 1)
    {
      status = sem_post(&sem);
    }
    usleep(50 * 1000);
  }
  sem_post(&sem);
  for (int i = 0; i < 8; ++i)
  {
    static uint8_t corr_cnt = 0;
    sem_wait(&sem);
    if (strcmp(RX_PAK, SYNC_ACK) == 0)
    {
      corr_cnt++;
    }
    if (corr_cnt == 7)
    {
      printf("tx_pthread: SYNC OK\n");
    }
  }

READ_MAC:

  /* ESP_READ_REG    0x3FF00050 */

  write(tx_fd, READ_ESP_OTP_MAC[0], (size_t) 14);
  sem_wait(&sem);

  for (int i = 8; i > 4; --i)
  {
    ESP_OTP_MAC0 = ((ESP_OTP_MAC0 <<  8) & 0xFFFFFF00) + RX_PAK[i];
  }
  printf("tx_pthread: 0x3FF00050: 0x%08X\n", ESP_OTP_MAC0);

  /* ESP_READ_REG    0x3FF00054 */

  write(tx_fd, READ_ESP_OTP_MAC[1], (size_t) 14);
  sem_wait(&sem);
  for (int i = 8; i > 4; --i)
  {
    ESP_OTP_MAC1 = ((ESP_OTP_MAC1 <<  8) & 0xFFFFFF00) + RX_PAK[i];
  }
  printf("tx_pthread: 0x3FF00054: 0x%08X\n", ESP_OTP_MAC1);

  /* ESP_READ_REG    0x3FF00058 */

  write(tx_fd, READ_ESP_OTP_MAC[2], (size_t) 14);
  sem_wait(&sem);
  for (int i = 8; i > 4; --i)
  {
    ESP_OTP_MAC2 = ((ESP_OTP_MAC2 <<  8) & 0xFFFFFF00) + RX_PAK[i];
  }
  printf("tx_pthread: 0x3FF00058: 0x%08X\n", ESP_OTP_MAC2);

  /* ESP_READ_REG    0x3FF0005C */

  write(tx_fd, READ_ESP_OTP_MAC[3], (size_t) 14);
  sem_wait(&sem);
  for (int i = 8; i > 4; --i)
  {
    ESP_OTP_MAC3 = ((ESP_OTP_MAC3 <<  8) & 0xFFFFFF00) + RX_PAK[i];
  }
  printf("tx_pthread: 0x3FF0005C: 0x%08X\n", ESP_OTP_MAC3);

  /* process MAC */

  if (ESP_OTP_MAC3 != 0)
  {
    MAC[0] = (ESP_OTP_MAC3 >> 16) & 0xFF;
    MAC[1] = (ESP_OTP_MAC3 >>  8) & 0xFF;
    MAC[2] = (ESP_OTP_MAC3 >>  0) & 0xFF;
  }
  else if (((ESP_OTP_MAC1 >> 16) & 0xFF) == 0)
  {
    MAC[0] = 0x18;
    MAC[1] = 0xFE;
    MAC[2] = 0x34;
  }
  else if (((ESP_OTP_MAC1 >> 16) & 0xFF) == 1)
  {
    MAC[0] = 0xAC;
    MAC[1] = 0xD0;
    MAC[2] = 0x74;
  }
  MAC[3] = (ESP_OTP_MAC1 >>  8) & 0xFF;
  MAC[4] = (ESP_OTP_MAC1 >>  0) & 0xFF;
  MAC[5] = (ESP_OTP_MAC0 >> 24) & 0xFF;

  sprintf(MAC_STR, "%02X%02X%02X%02X%02X%02X",
      MAC[0],MAC[1],MAC[2],MAC[3],MAC[4],MAC[5]);

  printf("tx_pthread: MAC: %s\n", MAC_STR);

  pthread_exit((pthread_addr_t) OK);
}

接收部分:

static void *rx_pthread(FAR void *parameter) {
  int rx_fd = (int) ((intptr_t) parameter);

  uint8_t RX_TMP;

  sem_wait(&sem);

  printf("rx_pthread: pending data under baudrate 74880\n");
  tcflush(rx_fd, TCIFLUSH);

  sem_wait(&sem);

  int index = 0;
  bool REC_PAK = FALSE;
  bool PAK_VAL = FALSE;
  while (1)
  {
    read(rx_fd, &RX_TMP, 1);

    if ((index == 0) && (RX_TMP == 0xC0))
    {
      REC_PAK = TRUE;
    }

    if (REC_PAK)
    {
      RX_PAK[index] = RX_TMP;
      ++index;
      if (index == 12)          // last byte
      {
        REC_PAK = FALSE;        // end a package
        index = 0;
        if (RX_TMP == 0xC0)     // last byte correct
        {
          PAK_VAL = TRUE;
          sem_post(&sem);
        } else
        {
          printf("rx_pthread: ERROR last byte\n", RX_TMP);
          memset(RX_PAK, 0x00, 12);
          break;
        }
      }

    }
  }
  pthread_exit((pthread_addr_t) OK);
}

编译运行。

nsh>esptool
esptool v1.0
Driver: /dev/gpout1
  Output pin:    Value=1
  Writing:       Value=0
  Verify:        Value=0
Driver: /dev/gpout0
  Output pin:    Value=0
  Writing:       Value=0
  Verify:        Value=0
Driver: /dev/gpout1
  Output pin:    Value=0
  Writing:       Value=1
  Verify:        Value=1
esp_sub_tool: tx_fd = 3
tx_pthread: tx_fd = 3
rx_pthread: first sem_wait over.
rx_pthread: pending data under baudrate 74880
rx_pthread: second sem_wait over.
tx_pthread: SYNC OK
tx_pthread: 0x3FF00050: 0xFF6A0000
tx_pthread: 0x3FF00054: 0x02001C1A
tx_pthread: 0x3FF00058: 0x4900B000
tx_pthread: 0x3FF0005C: 0x00A020A6
tx_pthread: MAC: A020A61C1AFF

用esptool工具直接读取MAC:

godenfreemans@godenfreemans-VirtualBox:~/NuttX/nuttx$ esptool.py read_mac
esptool.py v2.5.1
Found 1 serial ports
Serial port /dev/ttyUSB0
Connecting........_____....._
Detecting chip type... ESP8266
Chip is ESP8266EX
Features: WiFi
MAC: a0:20:a6:1c:1a:ff
Uploading stub...
Running stub...
Stub running...
MAC: a0:20:a6:1c:1a:ff
Hard resetting via RTS pin...

A020A61C1AFF == a0:20:a6:1c:1a:ff
读取MAC完成。

编辑起来有点卡了,新开一篇。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值