串口复用指南

更新时间:2022-11-24 09:20:19

SDK 开发中经常会遇到这么一类问题,I/O 不够用,需要将串口脚需要用作输出口控制,但模组串口又需要用作烧录授权,于是有了冲突。

本文档将以案例的方式介绍既不影响串口授权产品,又可以将串口用作输出控制的方法。本文已 BT3L 举例,其他泰凌微模组或其他芯片平台方案类似。

方案一

以 Telink 平台为例,要复用的脚为 GPI/O_PB1(UART TX),用作 PWM 输出。上电先进行 UART 初始化,若 1 秒内进入了授权产测则不将串口脚初始化为输出控制脚,若超时则将串口脚初始化为输出控制脚。

  • 该方案优点是简单,适用性广。
  • 该方案缺点是要复用的串口脚上电不能立即用作输出脚,需要等一段时间。
//app.c

uint32_t m_uart_muti_use_tick = 0;//定义全局变量

void user_init_normal(void)
{
	……
	uart_init(9600);
	……
	m_uart_muti_use_tick = clock_time();
}


void main_loop (void)
{
	static uint8_t PB1_init_flag =0;
	////////////////////////////////////// BLE entry /////////////////////////////////
	blt_sdk_main_loop();
	
	blt_soft_timer_process(MAINLOOP_ENTRY);


    if(clock_time_exceed(uart_muti_use_tick,1000*1000))
    {
        //init 
        if(PB1_init_flag==0)
        {
            PB1_init_flag = 1;
            gpI/O_set_func(GPI/O_PB1, AS_PWM4);
        	pwm_set_mode(PWM4_ID, PWM_NORMAL_MODE);
        	pwm_set_phase(PWM4_ID, 0);   //no phase at pwm beginning
        	pwm_set_cycle_and_duty(PWM4_ID, (u16) (1000 * CLOCK_SYS_CLOCK_1US),  (u16) (667 * CLOCK_SYS_CLOCK_1US) );
        	pwm_start(PWM4_ID);
    	}
    }
	……
}

//……\tuya_ble_sdk\app\product_test\tuya_ble_app_productI/On_test.c

/*********************************************************
FN: 是否处于产测中
*/
uint8_t tuya_ble_is_productI/On_test_effective(void)
{
	return tuya_ble_productI/On_test_flag;
}

效果如下:

串口复用指南

方案二

以 Telink 平台为例,要复用的脚为 GPI/O_PB1(UART TX),用作 PWM 输出。上电就将 GPI/O_PB1 用作 PWM,持续 1 秒的蓝牙扫描。若扫描到了广播名为 “ty_prod” 的广播,才初始化为串口。

  • 该方案的优点是上电就能用作输出控制。
  • 该方案的缺点是需要支持扫描,授权产测的时候需要插一个信标。
//add ty_ble_scan_tlsr825x.c


#include "tl_common.h"
#include "stack/ble/gap/gap.h"
#include "stack/ble/hci/hci_const.h"
#include "stack\ble\ll\ll_scan.h"
#include "stack\ble\ll\ll_whitelist.h"
static char  m_ble_target_periph_name[8] = "ty_prod";
typedef struct
{
	uint8_t     * p_data;    /**< Pointer to data. */
	uint16_t      data_len;  /**< Length of data. */
} data_t;

uint32_t adv_report_parse(uint8_t type, data_t * p_advdata, data_t * p_typedata)
{
    uint32_t  index = 0;
    uint8_t * p_data;
    p_data = p_advdata->p_data;
    while (index < p_advdata->data_len)
    {
        uint8_t field_length = p_data[index];
        uint8_t field_type   = p_data[index + 1];

        if (field_type == type)
        {
            p_typedata->p_data   = &p_data[index + 2];
            p_typedata->data_len = field_length - 1;
            return 0;//OPRT_OK
        }
        index += field_length + 1;
    }
    return 5;//OPRT_ERROR_NOT_FOUND
}

void tuya_ble_scan_evt_handler(uint32_t h, uint8_t *para, int n)
{
	event_adv_report_t *pa = (event_adv_report_t *)para;
	int8_t rssi = pa->data[pa->len];
	static uint8_t uart_init_flag = 0;
	data_t adv_data;
	data_t dev_name;
	adv_data.p_data = pa->data;
	adv_data.data_len = pa->len;

	if(0 == adv_report_parse(GAP_ADTYPE_LOCAL_NAME_COMPLETE,&adv_data,&dev_name))
	{
		if(memcmp(m_ble_target_periph_name,dev_name.p_data,dev_name.data_len)==0)
		{
			if(uart_init_flag==0)
			{
				uart_init_flag = 1;
				uart_init(9600);
			}
		}
	}
	else
	{

	}
}
extern int controller_event_handler(u32 h, u8 *para, int n);

void tuya_ble_scan_init(void)
{
    //scan set
    extern u8  mac_public[6];
	blc_ll_initScanning_module(mac_public);		//scan module: 		 optI/Onal
	blc_hci_le_setEventMask_cmd(HCI_LE_EVT_MASK_ADVERTISING_REPORT);
	
	//blc_hci_registerControllerEventHandler(tuya_ble_scan_evt_handler);		//register event callback
	
	blc_ll_setScanParameter(SCAN_TYPE_PASSIVE, SCAN_INTERVAL_30MS, SCAN_INTERVAL_30MS,
									  OWN_ADDRESS_PUBLIC, SCAN_FP_ALLOW_ADV_ANY);

}
uint8_t tuya_ble_scan_set_filter_name(char *bft_target_periph_name)
{
	memcpy(m_ble_target_periph_name,bft_target_periph_name,7);
}
void tuya_ble_scan_start(void)
{
	blc_hci_registerControllerEventHandler(tuya_ble_scan_evt_handler);		//register event callback
	blc_ll_addScanningInAdvState();  //add scan in adv state
	blc_ll_addScanningInConnSlaveRole();  //add scan in conn slave role
    blc_ll_setScanEnable (1, 0);
}
void tuya_ble_scan_stop(void)
{
	blc_hci_registerControllerEventHandler(controller_event_handler);		//register event callback	
	blc_ll_setScanEnable (0, 0);
	blc_ll_removeScanningFromAdvState();
	blc_ll_removeScanningFromConnSLaveRole();
}




//app.c

tuya_ble_timer_t first_init_scan_timer;

static void tuya_ble_first_init_scan_timeout_handler(tuya_ble_timer_t timer)
{
    tuya_ble_scan_stop();
}
void tuya_ble_first_init_scan_timer_start(void)
{
    static uint8_t init = 0;
    tuya_ble_timer_create(&first_init_scan_timer,2000,TUYA_BLE_TIMER_SINGLE_SHOT,tuya_ble_first_init_scan_timeout_handler);
    tuya_ble_timer_start(first_init_scan_timer);
    if(init==0)
    {
        init = 1;
        tuya_ble_scan_init();
    }
    tuya_ble_scan_start();
}

void user_init_normal(void)
{
	……
    gpI/O_set_func(GPI/O_PB1, AS_PWM4);
    pwm_set_mode(PWM4_ID, PWM_NORMAL_MODE);
    pwm_set_phase(PWM4_ID, 0);   //no phase at pwm beginning
    pwm_set_cycle_and_duty(PWM4_ID, (u16) (1000 * CLOCK_SYS_CLOCK_1US),  (u16) (667 * CLOCK_SYS_CLOCK_1US) );
    pwm_start(PWM4_ID);

	tuya_ble_first_init_scan_timer_start();
}