过往分享
RA4M2挑战赛分享:
【RA4M2设计挑战赛】1. RASC配置FreeRTOS
【RA4M2设计挑战赛】2. 硬件IIC读取HS3003的温湿度数据
【RA4M2设计挑战赛】3. 硬件IIC读取ISL29035采集光照强度
【RA4M2设计挑战赛】4. DA14531蓝牙模块使用
前言
瑞萨官方提供的WIFI模块DA16200上手起来有点慢,主要是没有一个完整的说明文档,很多东西都需要自己折腾,调试起来确实困难重重,主要是最开始模块都驱动不起来,最后才知道需要把reset引脚拉高,但是上手操作之后使用起来还是很方便的,支持ntp校时,支持mqtt,tcp等,这些使用起来都很方便,但是mqtt还存在一些问题,对阿里云,腾讯云等这些支持不是很好,导致有些命令直接不识别,这些都是后话,本文主要说明对DA16200的驱动
硬件连接
该模块使用起来其实还是挺方便的,直接连接之后就可以通信了,官方提供了专用的上位机可以用来调试,只不过有时候不识别,这个折腾了我很久,解决方法就是每次使用的时候将reset引脚接地复位一下就可以了。
硬件连接如下:
连接到了RA4M2的PMOD2上。
外设配置
软件使用了串口0,P410和P411,配置如下:
同时需要将P608配置为普通IO口作为输出模式,用于拉低reset引脚强制复位
建议每次启动的时候复位一下,防止芯片休眠,操作不了
软件驱动
软件驱动参考了官方的教程,但是官方的驱动代码逻辑较为复杂,我做了精简以及逻辑优化,AT命令交互速度更快。
da16200_AT.c
#include "hal_data.h"
#include "da16200_AT.h"
#include "app_common.h"
#include "app_led.h"
#include "app_wifi.h"
typedef struct
{
char at_buf[DA16200_STR_LEN_256];
uint16_t at_len;
uint16_t at_timeout;
} s_AtCmdBfType;
da16200_at_cmd_set_t g_da16200_cmd_set[] =
{
[DA16200_AT_CMD_INDEX_ATZ] =
{
.p_cmd = (uint8_t *) "ATZ\r\n",
.p_success_resp = (uint8_t *) "OK",
.max_resp_length = DA16200_STR_LEN_64,
.retry = DA16200_RETRY_VALUE_10,
.retry_delay = DA16200_DELAY_500MS,
.wait_timeout = DA16200_DELAY_1000MS
},
[DA16200_AT_CMD_INDEX_ATE] =
{
.p_cmd = (uint8_t *) "ATE\r\n",
.p_success_resp = (uint8_t *) "OK",
.max_resp_length = DA16200_STR_LEN_32,
.retry = DA16200_RETRY_VALUE_5,
.retry_delay = DA16200_DELAY_200MS,
.wait_timeout = DA16200_DELAY_1000MS
},
[ DA16200_AT_CMD_INDEX_AT_ATF] =
{
.p_cmd = (uint8_t *) "ATF\r\n",
.p_success_resp = (uint8_t *) "DONE",
.max_resp_length = DA16200_STR_LEN_128,
.retry = DA16200_RETRY_VALUE_5,
.retry_delay = DA16200_DELAY_500MS,
.wait_timeout = DA16200_DELAY_3000MS
},
[DA16200_AT_CMD_INDEX_AT_TMRFNOINIT] =
{
.p_cmd = (uint8_t *) "AT+TMRFNOINIT=0\r\n",
.p_success_resp = (uint8_t *) "OK",
.max_resp_length = DA16200_STR_LEN_32,
.retry = DA16200_RETRY_VALUE_5,
.retry_delay = DA16200_DELAY_200MS,
.wait_timeout = DA16200_DELAY_1000MS
},
[DA16200_AT_CMD_INDEX_AT_WFMODE] =
{
.p_cmd = (uint8_t *) "AT+WFMODE=0\r\n",
.p_success_resp = (uint8_t *) "OK",
.max_resp_length = DA16200_STR_LEN_32,
.retry = DA16200_RETRY_VALUE_5,
.retry_delay = DA16200_DELAY_200MS,
.wait_timeout = DA16200_DELAY_1000MS
},
[ DA16200_AT_CMD_INDEX_AT_RESTART] =
{
.p_cmd = (uint8_t *) "AT+RESTART\r\n",
.p_success_resp = (uint8_t *) "OK",
.max_resp_length = DA16200_STR_LEN_128,
.retry = DA16200_RETRY_VALUE_5,
.retry_delay = DA16200_DELAY_1000MS,
.wait_timeout = DA16200_DELAY_1000MS
},
[DA16200_AT_CMD_INDEX_AT_WFJAP] =
{
.p_cmd = (uint8_t *) "AT+WFJAP=hehungphone,4,1,1234543210\r\n",
.p_success_resp = (uint8_t *) "+WFJAP:1",
.max_resp_length = DA16200_STR_LEN_128,
.retry = DA16200_RETRY_VALUE_5,
.retry_delay = DA16200_DELAY_1000MS,
.wait_timeout = DA16200_DELAY_5000MS
},
[DA16200_AT_CMD_INDEX_AT_TRTC] =
{
.p_cmd = (uint8_t *) "AT+TRTC=183.230.40.40,1811,0\r\n",
.p_success_resp = (uint8_t *) "OK",
.max_resp_length = DA16200_STR_LEN_64,
.retry = DA16200_RETRY_VALUE_5,
.retry_delay = DA16200_DELAY_200MS,
.wait_timeout = DA16200_DELAY_2000MS
},
[DA16200_AT_CMD_INDEX_AT_TRTRM] =
{
.p_cmd = (uint8_t *) "AT+TRTRM=1\r\n",
.p_success_resp = (uint8_t *) "OK",
.max_resp_length = DA16200_STR_LEN_32,
.retry = DA16200_RETRY_VALUE_5,
.retry_delay = DA16200_DELAY_200MS,
.wait_timeout = DA16200_DELAY_1000MS
},
[DA16200_AT_CMD_INDEX_AT_WFCC] =
{
.p_cmd = (uint8_t *) "AT+WFCC=CH\r\n",
.p_success_resp = (uint8_t *) "OK",
.max_resp_length = DA16200_STR_LEN_32,
.retry = DA16200_RETRY_VALUE_5,
.retry_delay = DA16200_DELAY_200MS,
.wait_timeout = DA16200_DELAY_1000MS
},
[ DA16200_AT_CMD_INDEX_AT_WFSAP] =
{
.p_cmd = (uint8_t *) "AT+WFSAP=Renesas_Wifi,3,1,12345678,1,CH\r\n",
.p_success_resp = (uint8_t *) "OK",
.max_resp_length = DA16200_STR_LEN_128,
.retry = DA16200_RETRY_VALUE_5,
.retry_delay = DA16200_DELAY_200MS,
.wait_timeout = DA16200_DELAY_1000MS
},
[ DA16200_AT_CMD_INDEX_AT_NWIP] =
{
.p_cmd = (uint8_t *) "AT+NWIP=1,192.168.10.2,255.255.255.0,192.168.10.1\r\n",
.p_success_resp = (uint8_t *) "OK",
.max_resp_length = DA16200_STR_LEN_64,
.retry = DA16200_RETRY_VALUE_5,
.retry_delay = DA16200_DELAY_1000MS,
.wait_timeout = DA16200_DELAY_1000MS
},
[ DA16200_AT_CMD_INDEX_AT_NWDHS] =
{
.p_cmd = (uint8_t *) "AT+NWDHS=1\r\n",
.p_success_resp = (uint8_t *) "OK",
.max_resp_length = DA16200_STR_LEN_64,
.retry = DA16200_RETRY_VALUE_5,
.retry_delay = DA16200_DELAY_200MS,
.wait_timeout = DA16200_DELAY_1000MS
},
[ DA16200_AT_CMD_INDEX_AT_NWDHR] =
{
.p_cmd = (uint8_t *) "AT+NWDHR=192.168.10.3,192.168.10.10\r\n",
.p_success_resp = (uint8_t *) "OK",
.max_resp_length = DA16200_STR_LEN_64,
.retry = DA16200_RETRY_VALUE_5,
.retry_delay = DA16200_DELAY_200MS,
.wait_timeout = DA16200_DELAY_1000MS
},
[ DA16200_AT_CMD_INDEX_AT_TRTS] =
{
.p_cmd = (uint8_t *) "AT+TRTS=80\r\n",
.p_success_resp = (uint8_t *) "OK",
.max_resp_length = DA16200_STR_LEN_64,
.retry = DA16200_RETRY_VALUE_5,
.retry_delay = DA16200_DELAY_200MS,
.wait_timeout = DA16200_DELAY_1000MS
},
[ DA16200_AT_CMD_INDEX_AT_TRSAVE] =
{
.p_cmd = (uint8_t *) "AT+TRSAVE\r\n",
.p_success_resp = (uint8_t *) "OK",
.max_resp_length = DA16200_STR_LEN_32,
.retry = DA16200_RETRY_VALUE_5,
.retry_delay = DA16200_DELAY_200MS,
.wait_timeout = DA16200_DELAY_1000MS
},
[ DA16200_AT_CMD_INDEX_AT_WFSTA] =
{
.p_cmd = (uint8_t *) "AT+WFSTA\r\n",
.p_success_resp = (uint8_t *) "OK",
.max_resp_length = DA16200_STR_LEN_32,
.retry = DA16200_RETRY_VALUE_1,
.retry_delay = DA16200_DELAY_200MS,
.wait_timeout = DA16200_DELAY_1000MS
},
[ DA16200_AT_CMD_INDEX_AT_NWSNTP_START] =
{
.p_cmd = (uint8_t *) "AT+NWSNTP=1,pool.ntp.org,60\r\n",
.p_success_resp = (uint8_t *) "OK",
.max_resp_length = DA16200_STR_LEN_32,
.retry = DA16200_RETRY_VALUE_5,
.retry_delay = DA16200_DELAY_200MS,
.wait_timeout = DA16200_DELAY_1000MS
},
[ DA16200_AT_CMD_INDEX_AT_NWSNTP_STOP] =
{
.p_cmd = (uint8_t *) "AT+NWSNTP=0\r\n",
.p_success_resp = (uint8_t *) "OK",
.max_resp_length = DA16200_STR_LEN_32,
.retry = DA16200_RETRY_VALUE_5,
.retry_delay = DA16200_DELAY_200MS,
.wait_timeout = DA16200_DELAY_1000MS
},
[ DA16200_AT_CMD_INDEX_AT_NWSNTP_STATUS] =
{
.p_cmd = (uint8_t *) "AT+NWSNTP=?\r\n",
.p_success_resp = (uint8_t *) "OK",
.max_resp_length = DA16200_STR_LEN_32,
.retry = DA16200_RETRY_VALUE_5,
.retry_delay = DA16200_DELAY_200MS,
.wait_timeout = DA16200_DELAY_1000MS
},
[ DA16200_AT_CMD_INDEX_AT_TZONE_GET] =
{
.p_cmd = (uint8_t *) "AT+TZONE=?\r\n",
.p_success_resp = (uint8_t *) "OK",
.max_resp_length = DA16200_STR_LEN_64,
.retry = DA16200_RETRY_VALUE_5,
.retry_delay = DA16200_DELAY_100MS,
.wait_timeout = DA16200_DELAY_500MS
},
[ DA16200_AT_CMD_INDEX_AT_TZONE_SET] =
{
.p_cmd = (uint8_t *) "AT+TZONE=28800\r\n",
.p_success_resp = (uint8_t *) "OK",
.max_resp_length = DA16200_STR_LEN_64,
.retry = DA16200_RETRY_VALUE_5,
.retry_delay = DA16200_DELAY_100MS,
.wait_timeout = DA16200_DELAY_500MS
},
[ DA16200_AT_CMD_INDEX_AT_TIME_GET] =
{
.p_cmd = (uint8_t *) "AT+TIME=?\r\n",
.p_success_resp = (uint8_t *) "+TIME",
.max_resp_length = DA16200_STR_LEN_64,
.retry = DA16200_RETRY_VALUE_5,
.retry_delay = DA16200_DELAY_100MS,
.wait_timeout = DA16200_DELAY_500MS
},
[DA16200_AT_CMD_INDEX_AT_NWDHC] =
{
.p_cmd = (uint8_t *) "AT+NWDHC\r\n",
.p_success_resp = (uint8_t *) "OK",
.max_resp_length = DA16200_STR_LEN_32,
.retry = DA16200_RETRY_VALUE_5,
.retry_delay = DA16200_DELAY_100MS,
.wait_timeout = DA16200_DELAY_500MS
}
};
static uint32_t g_wifi_receive_time_count = 0;
static uint32_t count = 0;
static demo_data_t g_demo_data;
static s_AtCmdBfType g_at_buf;
static s_Da16200FbType RespList[] =
{
{Da16200_TRDTC_response, "+TRDTC:1"}
};
fsp_err_t Da1620_ATCommandExe(da16200_at_cmd_index_t at_cmd,
uint8_t *resp_buff)
{
uint16_t bytes_read = 0U;
uint16_t bytes_write;
fsp_err_t result = FSP_ERR_ASSERTION;
uint8_t retry_count = 0U;
da16200_at_cmd_set_t * p_cmd_set = g_da16200_cmd_set;
if (pdTRUE == xSemaphoreTake(wifi_mutex, portMAX_DELAY))
{
do
{
bytes_write = (uint16_t) strlen((char *) p_cmd_set[at_cmd].p_cmd);
wifi_serial_write((uint8_t*)p_cmd_set[at_cmd].p_cmd, bytes_write);
bytes_read = p_cmd_set[at_cmd].max_resp_length;
memset (resp_buff, 0, bytes_read);
result = wifi_serial_read(resp_buff,
&bytes_read,
(const char*)p_cmd_set[at_cmd].p_success_resp,
p_cmd_set[at_cmd].wait_timeout);
if (FSP_SUCCESS == result)
{
break;
}
DELAY_MS(p_cmd_set[at_cmd].retry_delay);
++retry_count;
}
while(retry_count < p_cmd_set[at_cmd].retry);
(void)xSemaphoreGive(wifi_mutex);
}
return result;
}
uint8_t is_str_present(const char * p_resp_str, const char * p_search_str)
{
if (strstr (p_resp_str, p_search_str))
{
return SF_WIFI_TRUE;
}
return SF_WIFI_FALSE;
}
fsp_err_t wifi_serial_read(uint8_t * p_dest,
const uint16_t * p_bytes,
const char * p_resp_ptr,
uint32_t timeout_ms)
{
fsp_err_t status = FSP_SUCCESS;
uint16_t bytes = *p_bytes;
uint16_t i;
uint8_t expected_resp_present;
g_wifi_receive_time_count = 0U;
do
{
if (g_at_buf.at_len >= strlen(p_resp_ptr))
{
if (g_at_buf.at_len >= bytes)
{
status = FSP_ERR_RXBUF_OVERFLOW;
break;
}
expected_resp_present = is_str_present(g_at_buf.at_buf, p_resp_ptr);
if(SF_WIFI_TRUE == expected_resp_present)
{
printf ("==>da16200 recv:%s\n", g_at_buf.at_buf);
status = FSP_SUCCESS;
break;
}
}
expected_resp_present = is_str_present(g_at_buf.at_buf, "ERROR");
if(SF_WIFI_TRUE == expected_resp_present)
{
printf ("==>da16200 error:%s\n", g_at_buf.at_buf);
status = FSP_ERR_ASSERTION;
break;
}
if(g_wifi_receive_time_count >= timeout_ms)
{
if (g_at_buf.at_len >= 0)
memset(g_at_buf.at_buf, '\0', sizeof(g_at_buf.at_buf));
g_wifi_receive_time_count = 0U;
status = FSP_ERR_TIMEOUT;
break;
}
DELAY_MS(1);
} while(1);
if (FSP_SUCCESS == status)
{
for (i = 0; i < g_at_buf.at_len; i++)
{
*p_dest = g_at_buf.at_buf[i];
p_dest ++;
}
}
return status;
}
fsp_err_t wifi_serial_write(uint8_t * p_src, uint16_t bytes)
{
fsp_err_t status = FSP_SUCCESS;
if (g_at_buf.at_len > 0U)
{
g_at_buf.at_len = 0U;
memset(g_at_buf.at_buf, '\0', sizeof(g_at_buf.at_buf));
}
status = g_uart0.p_api->write(g_uart0.p_ctrl, p_src, bytes);
return(status);
}
void uart0_notification(uart_callback_args_t *p_args)
{
if (p_args->event == UART_EVENT_RX_CHAR)
{
if (g_at_buf.at_len < (DA16200_STR_LEN_256 - 1U))
{
g_at_buf.at_buf[g_at_buf.at_len] = (uint8_t)p_args->data;
g_at_buf.at_len ++;
}
}
}
void timer0_1ms_callback(timer_callback_args_t *p_args)
{
FSP_PARAMETER_NOT_USED(p_args);
g_wifi_receive_time_count++;
g_demo_data.led_blink_count++;
if(g_demo_data.led_blink_count >= 1000)
{
count++;
g_demo_data.led_blink_count = 0;
if(count%2)
{
Led_Ctrl(LED_3, 1);
}
else
{
Led_Ctrl(LED_3, 0);
}
}
WIfi_CheckPreiodLoop();
}
void Da16200_FeedbackHandle(void)
{
uint8_t i;
for (i = 0; i < (sizeof(RespList) / sizeof(s_Da16200FbType)); i++)
{
if (SF_WIFI_TRUE == is_str_present(g_at_buf.at_buf, RespList->p_cmd))
{
RespList->RespFbFunc(g_at_buf.at_buf, g_at_buf.at_len);
}
}
if (g_at_buf.at_len > 0)
{
ENTER_CRITICAL();
memset(g_at_buf.at_buf, '\0', sizeof(g_at_buf.at_buf));
g_at_buf.at_len = 0;
EXIT_CRITICAL();
}
}
da16200_AT.h
#ifndef DA16200_AT_H_
#define DA16200_AT_H_
#include "hal_data.h"
#define DA16200_STR_LEN_8 (8U)
#define DA16200_STR_LEN_16 (16U)
#define DA16200_STR_LEN_32 (32U)
#define DA16200_STR_LEN_64 (64U)
#define DA16200_STR_LEN_128 (128U)
#define DA16200_STR_LEN_256 (256U)
#define DA16200_STR_LEN_512 (512U)
#define DA16200_DELAY_0 (0U)
#define DA16200_DELAY_20MS (20U)
#define DA16200_DELAY_50MS (50U)
#define DA16200_DELAY_100MS (100U)
#define DA16200_DELAY_200MS (200U)
#define DA16200_DELAY_300MS (300U)
#define DA16200_DELAY_500MS (500U)
#define DA16200_DELAY_1000MS (1000U)
#define DA16200_DELAY_2000MS (2000U)
#define DA16200_DELAY_3000MS (3000U)
#define DA16200_DELAY_4000MS (4000U)
#define DA16200_DELAY_5000MS (5000U)
#define DA16200_RETRY_VALUE_0 (0U)
#define DA16200_RETRY_VALUE_1 (1U)
#define DA16200_RETRY_VALUE_5 (5U)
#define DA16200_RETRY_VALUE_10 (10U)
#define SF_WIFI_TRUE (1U)
#define SF_WIFI_FALSE (0U)
typedef struct da16200_at_cmd_set
{
uint8_t * p_cmd;
uint8_t * p_success_resp;
uint16_t max_resp_length;
uint8_t retry;
uint16_t retry_delay;
uint16_t wait_timeout;
} da16200_at_cmd_set_t;
typedef enum da16200_at_cmd_index
{
DA16200_AT_CMD_INDEX_ATZ = 0,
DA16200_AT_CMD_INDEX_ATE,
DA16200_AT_CMD_INDEX_AT_ATF,
DA16200_AT_CMD_INDEX_AT_TMRFNOINIT,
DA16200_AT_CMD_INDEX_AT_WFMODE,
DA16200_AT_CMD_INDEX_AT_RESTART,
DA16200_AT_CMD_INDEX_AT_WFJAP,
DA16200_AT_CMD_INDEX_AT_TRTC,
DA16200_AT_CMD_INDEX_AT_TRTRM,
DA16200_AT_CMD_INDEX_AT_WFCC,
DA16200_AT_CMD_INDEX_AT_WFSAP,
DA16200_AT_CMD_INDEX_AT_NWIP,
DA16200_AT_CMD_INDEX_AT_NWDHS,
DA16200_AT_CMD_INDEX_AT_NWDHR,
DA16200_AT_CMD_INDEX_AT_TRTS,
DA16200_AT_CMD_INDEX_AT_TRSAVE,
DA16200_AT_CMD_INDEX_AT_WFSTA,
DA16200_AT_CMD_INDEX_AT_NWSNTP_START,
DA16200_AT_CMD_INDEX_AT_NWSNTP_STOP,
DA16200_AT_CMD_INDEX_AT_NWSNTP_STATUS,
DA16200_AT_CMD_INDEX_AT_TZONE_GET,
DA16200_AT_CMD_INDEX_AT_TZONE_SET,
DA16200_AT_CMD_INDEX_AT_TIME_GET,
DA16200_AT_CMD_INDEX_AT_NWDHC,
DA16200_AT_CMD_INDEX_AT_NONE
} da16200_at_cmd_index_t;
typedef struct
{
char * p_cmd;
void (*Da16200_AtCmdCbFunc)(char *resp_buf);
} s_Da16200AtCmdCbType;
typedef struct demo_data
{
uint8_t led_blink_flag;
uint16_t led_blink_count;
} demo_data_t;
typedef struct
{
void (*RespFbFunc)(char *resp_data, uint16_t resp_data_len);
char * p_cmd;
} s_Da16200FbType;
extern fsp_err_t wifi_serial_read(uint8_t * p_dest,
const uint16_t * p_bytes,
const char * p_resp_ptr,
uint32_t timeout_ms);
extern fsp_err_t wifi_serial_write(uint8_t * p_src, uint16_t bytes);
extern uint8_t is_str_present(const char * p_resp_str, const char * p_search_str);
extern fsp_err_t Da1620_ATCommandExe(da16200_at_cmd_index_t at_cmd, uint8_t *resp_buff);
extern void Da16200_FeedbackHandle(void);
#endif
上述代码只是对DA16200的操作的AT命令的执行以及识别逻辑,具体使用方法可以参考我的作品提交贴:
【RA4M2设计挑战赛】作品提交 - 环境检测网关设备
试验效果
试验效果可以参考我提交的作品:
【RA4M2设计挑战赛】作品提交 - 环境检测网关设备
总结
DA16200优点:
- 功耗低
- 集成度高,支持MQTT,TCP,SNTP等
- 使用方便
DA16200缺点:
- MQTT代码存在bug,阿里云,腾讯云,onenet mqtt连接都存在问题,阿里云是client id命令输入不了,会返回error -3,腾讯云是返回error -4,onenet mqtt命令没问题但是启动不了mqtt(可能是我的自己操作问题)
- SNTP有时候更新很慢,如果上电的时候不发送ATF命令将NVM数据擦除,则SNTP很常见都更新不了