first submission
This commit is contained in:
@@ -0,0 +1,909 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
|
||||
*
|
||||
* Attention: This software (modified or not) and binary are used for
|
||||
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
|
||||
*/
|
||||
|
||||
/*********************************************************************
|
||||
* INCLUDES
|
||||
*/
|
||||
#include "CONFIG.h"
|
||||
#include "devinfoservice.h"
|
||||
#include "ancs_client.h"
|
||||
#include "ancs_client_internal.h"
|
||||
#include "ancs.h"
|
||||
|
||||
/*********************************************************************
|
||||
* MACROS
|
||||
*/
|
||||
|
||||
// Length of bd addr as a string
|
||||
#define B_ADDR_STR_LEN 15
|
||||
|
||||
/*********************************************************************
|
||||
* CONSTANTS
|
||||
*/
|
||||
// What is the advertising interval when device is discoverable (units of 625us, 80=50ms)
|
||||
#define DEFAULT_ADVERTISING_INTERVAL 80
|
||||
|
||||
// Minimum connection interval (units of 1.25ms, 6=7.5ms)
|
||||
#define DEFAULT_DESIRED_MIN_CONN_INTERVAL 6
|
||||
|
||||
// Maximum connection interval (units of 1.25ms, 100=125ms)
|
||||
#define DEFAULT_DESIRED_MAX_CONN_INTERVAL 100
|
||||
|
||||
// Slave latency to use parameter update
|
||||
#define DEFAULT_DESIRED_SLAVE_LATENCY 0
|
||||
|
||||
|
||||
// Minimum connection interval (units of 1.25ms)
|
||||
#define DEFAULT_UPDATE_MIN_CONN_INTERVAL 24
|
||||
|
||||
// Maximum connection interval (units of 1.25ms)
|
||||
#define DEFAULT_UPDATE_MAX_CONN_INTERVAL 40
|
||||
|
||||
// Slave latency to use parameter update
|
||||
#define DEFAULT_UPDATE_SLAVE_LATENCY 0
|
||||
|
||||
// Supervision timeout value (units of 10ms)
|
||||
#define DEFAULT_UPDATE_CONN_TIMEOUT 42
|
||||
|
||||
// Default parameter update delay in 0.625ms
|
||||
#define DEFAULT_PARAM_UPDATE_DELAY 3200
|
||||
|
||||
// Default phy update delay in 0.625ms
|
||||
#define DEFAULT_PHY_UPDATE_DELAY 2400
|
||||
|
||||
// ANCS Service: 7905F431-B5CE-4E99-A40F-4B1E122D00D0
|
||||
#define ANCS_SVC_UUID 0xD0, 0x00, 0x2D, 0x12, 0x1E, 0x4B, 0x0F, 0xA4, 0x99, 0x4E, 0xCE, 0xB5, 0x31, 0xF4, 0x05, 0x79
|
||||
|
||||
// Notification Source: UUID 9FBF120D-6301-42D9-8C58-25E699A21DBD (notifiable)
|
||||
#define ANCS_NOTIF_SRC_CHAR_UUID 0x1DBD // Last 2 bytes of the 128bit-16bytes UUID
|
||||
|
||||
// Control point: UUID 69D1D8F3-45E1-49A8-9821-9BBDFDAAD9D9 (writeable with response)
|
||||
#define ANCS_CTRL_PT_CHAR_UUID 0xD9D9
|
||||
|
||||
// Data Source: UUID 22EAC6E9-24D6-4BB5-BE44-B36ACE7C7BFB (notifiable)
|
||||
#define ANCS_DATA_SRC_CHAR_UUID 0x7BFB
|
||||
|
||||
#define CHAR_DESC_HDL_UUID128_LEN 21 // 5 + 16bytes = 21
|
||||
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
* TYPEDEFS
|
||||
*/
|
||||
|
||||
/*********************************************************************
|
||||
* GLOBAL VARIABLES
|
||||
*/
|
||||
uint16_t Ancs_handleCache[HDL_CACHE_LEN];
|
||||
|
||||
// Task ID for internal task/event processing
|
||||
uint8_t ancs_taskid;
|
||||
/*********************************************************************
|
||||
* EXTERNAL VARIABLES
|
||||
*/
|
||||
|
||||
/*********************************************************************
|
||||
* EXTERNAL FUNCTIONS
|
||||
*/
|
||||
|
||||
/*********************************************************************
|
||||
* LOCAL VARIABLES
|
||||
*/
|
||||
struct bt_ancs_client ancs_c;
|
||||
|
||||
// GAP - SCAN RSP data (max size = 31 bytes)
|
||||
static uint8_t scanRspData[] = {
|
||||
// complete name
|
||||
0x05, // length of this data
|
||||
GAP_ADTYPE_LOCAL_NAME_COMPLETE,
|
||||
'A',
|
||||
'N',
|
||||
'C',
|
||||
'S',
|
||||
|
||||
// connection interval range
|
||||
0x05, // length of this data
|
||||
GAP_ADTYPE_SLAVE_CONN_INTERVAL_RANGE,
|
||||
LO_UINT16(DEFAULT_DESIRED_MIN_CONN_INTERVAL), // 100ms
|
||||
HI_UINT16(DEFAULT_DESIRED_MIN_CONN_INTERVAL),
|
||||
LO_UINT16(DEFAULT_DESIRED_MAX_CONN_INTERVAL), // 1s
|
||||
HI_UINT16(DEFAULT_DESIRED_MAX_CONN_INTERVAL),
|
||||
|
||||
// Tx power level
|
||||
0x02, // length of this data
|
||||
GAP_ADTYPE_POWER_LEVEL,
|
||||
0 // 0dBm
|
||||
};
|
||||
|
||||
// GAP - Advertisement data (max size = 31 bytes, though this is
|
||||
// best kept short to conserve power while advertising)
|
||||
static uint8_t advertData[] = {
|
||||
// Flags; this sets the device to use limited discoverable
|
||||
// mode (advertises for 30 seconds at a time) instead of general
|
||||
// discoverable mode (advertises indefinitely)
|
||||
0x02, // length of this data
|
||||
GAP_ADTYPE_FLAGS,
|
||||
GAP_ADTYPE_FLAGS_LIMITED | GAP_ADTYPE_FLAGS_BREDR_NOT_SUPPORTED,
|
||||
|
||||
// service UUID, to notify central devices what services are included
|
||||
// in this peripheral
|
||||
0x11, // length of this data
|
||||
GAP_ADTYPE_SERVICES_LIST_128BIT, // some of the UUID's, but not all
|
||||
ANCS_SVC_UUID,
|
||||
|
||||
0x05,
|
||||
GAP_ADTYPE_LOCAL_NAME_COMPLETE,
|
||||
'A', 'N', 'C', 'S',
|
||||
};
|
||||
|
||||
|
||||
|
||||
// Connection handle of current connection
|
||||
static peripheralConnItem_t ancs_conn_list = {
|
||||
.connHandle = GAP_CONNHANDLE_INIT
|
||||
};
|
||||
|
||||
|
||||
static uint8_t discoveryState = DISC_ANCS_START;
|
||||
|
||||
// GAP GATT Attributes
|
||||
static uint8_t attDeviceName[GAP_DEVICE_NAME_LEN] = "ANCS";
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
* LOCAL FUNCTIONS
|
||||
*/
|
||||
uint16_t ANCS_ProcessEvent(uint8_t task_id, uint16_t events);
|
||||
static void AncsProcessTMOSMsg(tmos_event_hdr_t *pMsg);
|
||||
static void AncsApp_discoverService(gattMsgEvent_t *pMsg);
|
||||
static void AncsStateNotificationCB(gapRole_States_t newState, gapRoleEvent_t *pEvent);
|
||||
static void AncsParamUpdateCB(uint16_t connHandle, uint16_t connInterval,
|
||||
uint16_t connSlaveLatency, uint16_t connTimeout);
|
||||
static void AncsPasscodeCB(uint8_t *deviceAddr, uint16_t connectionHandle,
|
||||
uint8_t uiInputs, uint8_t uiOutputs);
|
||||
static void AncsPairStateCB(uint16_t connHandle, uint8_t state, uint8_t status);
|
||||
|
||||
/*********************************************************************
|
||||
* PROFILE CALLBACKS
|
||||
*/
|
||||
|
||||
// GAP Role Callbacks
|
||||
static gapRolesCBs_t AncsPeripheralCBs = {
|
||||
AncsStateNotificationCB, // Profile State Change Callbacks
|
||||
NULL, // When a valid RSSI is read from controller (not used by application)
|
||||
AncsParamUpdateCB
|
||||
};
|
||||
|
||||
// Bond Manager Callbacks
|
||||
static gapBondCBs_t AncsBondCB = {
|
||||
AncsPasscodeCB,
|
||||
AncsPairStateCB
|
||||
};
|
||||
|
||||
static struct bt_ancs_subscribe_cb *bt_ancs_subscribe;
|
||||
|
||||
void ancs_subscribe_cb_register(struct bt_ancs_subscribe_cb *cb)
|
||||
{
|
||||
bt_ancs_subscribe = cb;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* @fn peripheral_ancs_client_init
|
||||
*
|
||||
* @brief Initialization function for the Central App Task.
|
||||
* This is called during initialization and should contain
|
||||
* any application specific initialization (ie. hardware
|
||||
* initialization/setup, table initialization, power up
|
||||
* notification).
|
||||
*
|
||||
* @param task_id - the ID assigned by TMOS. This ID should be
|
||||
* used to send messages and set timers.
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
void peripheral_ancs_client_init(void)
|
||||
{
|
||||
ancs_taskid = TMOS_ProcessEventRegister(ANCS_ProcessEvent);
|
||||
|
||||
// Setup the GAP Peripheral Role Profile
|
||||
{
|
||||
uint8_t initial_advertising_enable = TRUE;
|
||||
uint16_t desired_min_interval = DEFAULT_DESIRED_MIN_CONN_INTERVAL;
|
||||
uint16_t desired_max_interval = DEFAULT_DESIRED_MAX_CONN_INTERVAL;
|
||||
|
||||
// Set the GAP Role Parameters
|
||||
GAPRole_SetParameter(GAPROLE_ADVERT_ENABLED, sizeof(uint8_t), &initial_advertising_enable);
|
||||
GAPRole_SetParameter(GAPROLE_SCAN_RSP_DATA, sizeof(scanRspData), scanRspData);
|
||||
GAPRole_SetParameter(GAPROLE_ADVERT_DATA, sizeof(advertData), advertData);
|
||||
GAPRole_SetParameter(GAPROLE_MIN_CONN_INTERVAL, sizeof(uint16_t), &desired_min_interval);
|
||||
GAPRole_SetParameter(GAPROLE_MAX_CONN_INTERVAL, sizeof(uint16_t), &desired_max_interval);
|
||||
}
|
||||
|
||||
// Set the GAP Characteristics
|
||||
GGS_SetParameter(GGS_DEVICE_NAME_ATT, GAP_DEVICE_NAME_LEN, attDeviceName);
|
||||
|
||||
{
|
||||
uint16_t advInt = DEFAULT_ADVERTISING_INTERVAL;
|
||||
|
||||
// Set advertising interval
|
||||
GAP_SetParamValue(TGAP_DISC_ADV_INT_MIN, advInt);
|
||||
GAP_SetParamValue(TGAP_DISC_ADV_INT_MAX, advInt);
|
||||
|
||||
// Enable scan req notify
|
||||
GAP_SetParamValue(TGAP_ADV_SCAN_REQ_NOTIFY, ENABLE);
|
||||
}
|
||||
|
||||
// Setup the GAP Bond Manager
|
||||
{
|
||||
uint32_t passkey = 0; // passkey "000000"
|
||||
uint8_t pairMode = GAPBOND_PAIRING_MODE_WAIT_FOR_REQ;
|
||||
uint8_t mitm = TRUE;
|
||||
uint8_t bonding = TRUE;
|
||||
uint8_t ioCap = GAPBOND_IO_CAP_DISPLAY_ONLY;
|
||||
GAPBondMgr_SetParameter(GAPBOND_PERI_DEFAULT_PASSCODE, sizeof(uint32_t), &passkey);
|
||||
GAPBondMgr_SetParameter(GAPBOND_PERI_PAIRING_MODE, sizeof(uint8_t), &pairMode);
|
||||
GAPBondMgr_SetParameter(GAPBOND_PERI_MITM_PROTECTION, sizeof(uint8_t), &mitm);
|
||||
GAPBondMgr_SetParameter(GAPBOND_PERI_IO_CAPABILITIES, sizeof(uint8_t), &ioCap);
|
||||
GAPBondMgr_SetParameter(GAPBOND_PERI_BONDING_ENABLED, sizeof(uint8_t), &bonding);
|
||||
}
|
||||
|
||||
// Initialize GATT Client
|
||||
GATT_InitClient();
|
||||
// Register to receive incoming ATT Indications/Notifications
|
||||
GATT_RegisterForInd(ancs_taskid);
|
||||
|
||||
// Initialize GATT attributes
|
||||
GGS_AddService(GATT_ALL_SERVICES); // GAP
|
||||
GATTServApp_AddService(GATT_ALL_SERVICES); // GATT attributes
|
||||
DevInfo_AddService();
|
||||
|
||||
// Setup a delayed profile startup
|
||||
tmos_set_event(ancs_taskid, START_DEVICE_EVT);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* @fn Central_ProcessEvent
|
||||
*
|
||||
* @brief Central Application Task event processor. This function
|
||||
* is called to process all events for the task. Events
|
||||
* include timers, messages and any other user defined events.
|
||||
*
|
||||
* @param task_id - The TMOS assigned task ID.
|
||||
* @param events - events to process. This is a bit map and can
|
||||
* contain more than one event.
|
||||
*
|
||||
* @return events not processed
|
||||
*/
|
||||
uint16_t ANCS_ProcessEvent(uint8_t task_id, uint16_t events)
|
||||
{
|
||||
if(events & SYS_EVENT_MSG)
|
||||
{
|
||||
uint8_t *pMsg;
|
||||
|
||||
if((pMsg = tmos_msg_receive(ancs_taskid)) != NULL)
|
||||
{
|
||||
AncsProcessTMOSMsg((tmos_event_hdr_t *)pMsg);
|
||||
// Release the TMOS message
|
||||
tmos_msg_deallocate(pMsg);
|
||||
}
|
||||
// return unprocessed events
|
||||
return (events ^ SYS_EVENT_MSG);
|
||||
}
|
||||
|
||||
if(events & START_DEVICE_EVT)
|
||||
{
|
||||
// Start the Device
|
||||
GAPRole_PeripheralStartDevice(ancs_taskid, &AncsBondCB, &AncsPeripheralCBs);
|
||||
return (events ^ START_DEVICE_EVT);
|
||||
}
|
||||
|
||||
if(events & START_SUBSCRIPE_NOTIDATA_EVT)
|
||||
{
|
||||
int err ;
|
||||
if((err = bt_ancs_subscribe_data_source(&ancs_c,
|
||||
bt_ancs_subscribe->data_source)) != SUCCESS){
|
||||
if(err != -EALREADY)
|
||||
tmos_start_task(ancs_taskid, START_SUBSCRIPE_NOTIDATA_EVT, MS1_TO_SYSTEM_TIME(100));
|
||||
}
|
||||
return (events ^ START_SUBSCRIPE_NOTIDATA_EVT);
|
||||
}
|
||||
|
||||
if(events & START_SUBSCRIPE_NOTISRC_EVT)
|
||||
{
|
||||
int err ;
|
||||
if((err = bt_ancs_subscribe_notification_source(&ancs_c,
|
||||
bt_ancs_subscribe->notification_source)) != SUCCESS){
|
||||
if(err != -EALREADY)
|
||||
tmos_start_task(ancs_taskid, START_SUBSCRIPE_NOTISRC_EVT, MS1_TO_SYSTEM_TIME(100));
|
||||
}
|
||||
return (events ^ START_SUBSCRIPE_NOTISRC_EVT);
|
||||
}
|
||||
|
||||
|
||||
if(events & START_DISCOVER_EVT)
|
||||
{
|
||||
AncsApp_discoverService(NULL);
|
||||
return (events ^ START_DISCOVER_EVT);
|
||||
}
|
||||
|
||||
|
||||
|
||||
if(events & START_PARAM_UPDATE_EVT)
|
||||
{
|
||||
// start connect parameter update
|
||||
GAPRole_PeripheralConnParamUpdateReq(ancs_conn_list.connHandle,
|
||||
DEFAULT_UPDATE_MIN_CONN_INTERVAL,
|
||||
DEFAULT_UPDATE_MAX_CONN_INTERVAL,
|
||||
DEFAULT_UPDATE_SLAVE_LATENCY,
|
||||
DEFAULT_UPDATE_CONN_TIMEOUT,
|
||||
ancs_taskid);
|
||||
return (events ^ START_PARAM_UPDATE_EVT);
|
||||
}
|
||||
|
||||
if(events & START_PHY_UPDATE_EVT)
|
||||
{
|
||||
// start phy update
|
||||
PRINT("PHY Update %x...\n", GAPRole_UpdatePHY(ancs_conn_list.connHandle, 0, GAP_PHY_BIT_LE_2M,
|
||||
GAP_PHY_BIT_LE_2M, 0));
|
||||
|
||||
return (events ^ START_PHY_UPDATE_EVT);
|
||||
}
|
||||
|
||||
// Discard unknown events
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
* @fn centralProcessGATTMsg
|
||||
*
|
||||
* @brief Process GATT messages
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
static void AncsProcessGATTMsg(gattMsgEvent_t *pMsg)
|
||||
{
|
||||
if(!atomic_test_bit(&ancs_c.state, ANCS_BT_CONNECTED)){
|
||||
// In case a GATT message came after a connection has dropped,
|
||||
// ignore the message
|
||||
GATT_bm_free(&pMsg->msg, pMsg->method);
|
||||
return;
|
||||
}
|
||||
|
||||
if(!atomic_test_bit(&ancs_c.state, ANCS_BT_DISCOVERY_COMPLETE)){
|
||||
AncsApp_discoverService(pMsg);
|
||||
} else if (pMsg->method == ATT_HANDLE_VALUE_NOTI ||
|
||||
pMsg->method == ATT_HANDLE_VALUE_IND) {
|
||||
// Now in ancs_client.c
|
||||
Ancs_handleNotification(pMsg);
|
||||
} else if ((pMsg->method == ATT_READ_RSP) ||
|
||||
((pMsg->method == ATT_ERROR_RSP) &&
|
||||
(pMsg->msg.errorRsp.reqOpcode == ATT_READ_REQ))){
|
||||
|
||||
} else if((pMsg->method == ATT_WRITE_RSP) ||
|
||||
((pMsg->method == ATT_ERROR_RSP) &&
|
||||
(pMsg->msg.errorRsp.reqOpcode == ATT_WRITE_REQ))){
|
||||
bt_ancs_write_cb write_cb;
|
||||
|
||||
write_cb = ancs_c.cp_write_cb;
|
||||
atomic_clear_bit(&ancs_c.state, ANCS_CP_WRITE_PENDING);
|
||||
if (write_cb) {
|
||||
write_cb(&ancs_c, pMsg->msg.errorRsp.errCode);
|
||||
}
|
||||
} else if(pMsg->method == ATT_ERROR_RSP){
|
||||
PRINT("response %#x error: %#x\n", pMsg->msg.errorRsp.reqOpcode,
|
||||
pMsg->msg.errorRsp.errCode);
|
||||
}
|
||||
|
||||
GATT_bm_free(&pMsg->msg, pMsg->method);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* @fn central_ProcessTMOSMsg
|
||||
*
|
||||
* @brief Process an incoming task message.
|
||||
*
|
||||
* @param pMsg - message to process
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
static void AncsProcessTMOSMsg(tmos_event_hdr_t *pMsg)
|
||||
{
|
||||
switch(pMsg->event)
|
||||
{
|
||||
case GATT_MSG_EVENT:
|
||||
AncsProcessGATTMsg((gattMsgEvent_t *)pMsg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* @fn Peripheral_LinkEstablished
|
||||
*
|
||||
* @brief Process link established.
|
||||
*
|
||||
* @param pEvent - event to process
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
static void Peripheral_LinkEstablished(gapRoleEvent_t *pEvent)
|
||||
{
|
||||
gapEstLinkReqEvent_t *event = (gapEstLinkReqEvent_t *)pEvent;
|
||||
|
||||
// See if already connected
|
||||
if(ancs_conn_list.connHandle != GAP_CONNHANDLE_INIT)
|
||||
{
|
||||
GAPRole_TerminateLink(pEvent->linkCmpl.connectionHandle);
|
||||
PRINT("Connection max...\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
ancs_conn_list.connHandle = event->connectionHandle;
|
||||
ancs_conn_list.connInterval = event->connInterval;
|
||||
ancs_conn_list.connSlaveLatency = event->connLatency;
|
||||
ancs_conn_list.connTimeout = event->connTimeout;
|
||||
|
||||
ancs_c.conn = ancs_conn_list.connHandle;
|
||||
atomic_set_bit(&ancs_c.state, ANCS_BT_CONNECTED);
|
||||
|
||||
// Set timer for param update event
|
||||
tmos_start_task(ancs_taskid, START_PARAM_UPDATE_EVT, DEFAULT_PARAM_UPDATE_DELAY);
|
||||
|
||||
|
||||
discoveryState = DISC_ANCS_START;
|
||||
PRINT("Conn: %d - params: %d %d %d\n", event->connectionHandle,
|
||||
event->connInterval, event->connLatency, event->connTimeout);
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* @fn Peripheral_LinkTerminated
|
||||
*
|
||||
* @brief Process link terminated.
|
||||
*
|
||||
* @param pEvent - event to process
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
static void Peripheral_LinkTerminated(gapRoleEvent_t *pEvent)
|
||||
{
|
||||
gapTerminateLinkEvent_t *event = (gapTerminateLinkEvent_t *)pEvent;
|
||||
|
||||
if(event->connectionHandle == ancs_conn_list.connHandle)
|
||||
{
|
||||
ancs_conn_list.connHandle = GAP_CONNHANDLE_INIT;
|
||||
ancs_conn_list.connInterval = 0;
|
||||
ancs_conn_list.connSlaveLatency = 0;
|
||||
ancs_conn_list.connTimeout = 0;
|
||||
|
||||
// Restart advertising
|
||||
{
|
||||
uint8_t advertising_enable = TRUE;
|
||||
GAPRole_SetParameter(GAPROLE_ADVERT_ENABLED, sizeof(uint8_t), &advertising_enable);
|
||||
}
|
||||
|
||||
ancs_reinit(&ancs_c);
|
||||
}
|
||||
else
|
||||
{
|
||||
PRINT("ERR..\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void AncsParamUpdateCB(uint16_t connHandle, uint16_t connInterval,
|
||||
uint16_t connSlaveLatency, uint16_t connTimeout)
|
||||
{
|
||||
if(connHandle == ancs_conn_list.connHandle)
|
||||
{
|
||||
ancs_conn_list.connInterval = connInterval;
|
||||
ancs_conn_list.connSlaveLatency = connSlaveLatency;
|
||||
ancs_conn_list.connTimeout = connTimeout;
|
||||
|
||||
PRINT("update: %d - params: %d %d %d\n", connHandle,
|
||||
connInterval, connSlaveLatency, connTimeout);
|
||||
}
|
||||
else
|
||||
{
|
||||
PRINT("ERR..\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void AncsStateNotificationCB(gapRole_States_t newState, gapRoleEvent_t *pEvent)
|
||||
{
|
||||
switch(newState & GAPROLE_STATE_ADV_MASK)
|
||||
{
|
||||
case GAPROLE_STARTED:
|
||||
PRINT("Initialized..\n");
|
||||
break;
|
||||
|
||||
case GAPROLE_ADVERTISING:
|
||||
if(pEvent->gap.opcode == GAP_LINK_TERMINATED_EVENT)
|
||||
{
|
||||
Peripheral_LinkTerminated(pEvent);
|
||||
PRINT("Disconnected.. Reason:%x\n", pEvent->linkTerminate.reason);
|
||||
PRINT("Advertising..\n");
|
||||
}
|
||||
else if(pEvent->gap.opcode == GAP_MAKE_DISCOVERABLE_DONE_EVENT)
|
||||
{
|
||||
PRINT("Advertising..\n");
|
||||
}
|
||||
break;
|
||||
|
||||
case GAPROLE_CONNECTED:
|
||||
if(pEvent->gap.opcode == GAP_LINK_ESTABLISHED_EVENT)
|
||||
{
|
||||
Peripheral_LinkEstablished(pEvent);
|
||||
PRINT("Connected..\n");
|
||||
}
|
||||
break;
|
||||
|
||||
case GAPROLE_CONNECTED_ADV:
|
||||
if(pEvent->gap.opcode == GAP_MAKE_DISCOVERABLE_DONE_EVENT)
|
||||
{
|
||||
PRINT("Connected Advertising..\n");
|
||||
}
|
||||
break;
|
||||
|
||||
case GAPROLE_WAITING:
|
||||
if(pEvent->gap.opcode == GAP_END_DISCOVERABLE_DONE_EVENT)
|
||||
{
|
||||
PRINT("Waiting for advertising..\n");
|
||||
}
|
||||
else if(pEvent->gap.opcode == GAP_LINK_TERMINATED_EVENT)
|
||||
{
|
||||
Peripheral_LinkTerminated(pEvent);
|
||||
PRINT("Disconnected.. Reason:%x\n", pEvent->linkTerminate.reason);
|
||||
}
|
||||
else if(pEvent->gap.opcode == GAP_LINK_ESTABLISHED_EVENT)
|
||||
{
|
||||
if(pEvent->gap.hdr.status != SUCCESS)
|
||||
{
|
||||
PRINT("Waiting for advertising..\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
PRINT("Error..\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
PRINT("Error..%x\n", pEvent->gap.opcode);
|
||||
}
|
||||
break;
|
||||
|
||||
case GAPROLE_ERROR:
|
||||
PRINT("Error..\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* @fn pairStateCB
|
||||
*
|
||||
* @brief Pairing state callback.
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
static void AncsPairStateCB(uint16_t connHandle, uint8_t state, uint8_t status)
|
||||
{
|
||||
if(state == GAPBOND_PAIRING_STATE_STARTED)
|
||||
{
|
||||
PRINT("Pairing started:%d\n", status);
|
||||
}
|
||||
else if(state == GAPBOND_PAIRING_STATE_COMPLETE)
|
||||
{
|
||||
if(status == SUCCESS)
|
||||
{
|
||||
PRINT("Pairing success\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
PRINT("Pairing fail\n");
|
||||
}
|
||||
}
|
||||
else if(state == GAPBOND_PAIRING_STATE_BONDED)
|
||||
{
|
||||
if(status == SUCCESS)
|
||||
{
|
||||
PRINT("Bonding success\n");
|
||||
tmos_set_event(ancs_taskid, START_DISCOVER_EVT);
|
||||
}
|
||||
}
|
||||
else if(state == GAPBOND_PAIRING_STATE_BOND_SAVED)
|
||||
{
|
||||
if(status == SUCCESS)
|
||||
{
|
||||
PRINT("Bond save success\n");
|
||||
|
||||
tmos_set_event(ancs_taskid, START_DISCOVER_EVT);
|
||||
}
|
||||
else
|
||||
{
|
||||
PRINT("Bond save failed: %d\n", status);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* @fn centralPasscodeCB
|
||||
*
|
||||
* @brief Passcode callback.
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
static void AncsPasscodeCB(uint8_t *deviceAddr, uint16_t connectionHandle,
|
||||
uint8_t uiInputs, uint8_t uiOutputs)
|
||||
{
|
||||
uint32_t passcode;
|
||||
|
||||
// Create random passcode
|
||||
passcode = tmos_rand();
|
||||
passcode %= 1000000;
|
||||
// Display passcode to user
|
||||
if(uiOutputs != 0)
|
||||
{
|
||||
PRINT("Passcode:%06d\n", (int)passcode);
|
||||
}
|
||||
// Send passcode response
|
||||
GAPBondMgr_PasscodeRsp(connectionHandle, SUCCESS, passcode);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
* @fn centralGATTDiscoveryEvent
|
||||
*
|
||||
* @brief Process GATT discovery event
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
static void AncsApp_discoverService(gattMsgEvent_t *pMsg)
|
||||
{
|
||||
|
||||
static uint16_t Ancs_svcStartHdl;
|
||||
static uint16_t Ancs_svcEndHdl;
|
||||
static uint8_t Ancs_endHdlIdx;
|
||||
static uint8_t isNotifCCCD = FALSE;
|
||||
|
||||
switch (discoveryState)
|
||||
{
|
||||
case DISC_ANCS_START:
|
||||
{
|
||||
uint8_t uuid[ATT_UUID_SIZE] = {ANCS_SVC_UUID};
|
||||
|
||||
// Initialize service discovery variables
|
||||
Ancs_svcStartHdl = Ancs_svcEndHdl = 0;
|
||||
Ancs_endHdlIdx = 0;
|
||||
|
||||
// Discover ANCS service by UUID
|
||||
GATT_DiscPrimaryServiceByUUID(ancs_c.conn, uuid,
|
||||
ATT_UUID_SIZE, ancs_taskid);
|
||||
|
||||
discoveryState = DISC_ANCS_SVC;
|
||||
}
|
||||
break;
|
||||
|
||||
case DISC_ANCS_SVC:
|
||||
// Service found, store handles
|
||||
if (pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP &&
|
||||
pMsg->msg.findByTypeValueRsp.numInfo > 0)
|
||||
{
|
||||
Ancs_svcStartHdl =
|
||||
ATT_ATTR_HANDLE(pMsg->msg.findByTypeValueRsp.pHandlesInfo, 0);
|
||||
Ancs_svcEndHdl =
|
||||
ATT_GRP_END_HANDLE(pMsg->msg.findByTypeValueRsp.pHandlesInfo, 0);
|
||||
}
|
||||
|
||||
// If procedure complete
|
||||
if ((pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP &&
|
||||
pMsg->hdr.status == bleProcedureComplete) ||
|
||||
(pMsg->method == ATT_ERROR_RSP))
|
||||
{
|
||||
// If service found
|
||||
if (Ancs_svcStartHdl != 0)
|
||||
{
|
||||
// Discover all characteristics
|
||||
GATT_DiscAllChars(pMsg->connHandle, Ancs_svcStartHdl,
|
||||
Ancs_svcEndHdl, ancs_taskid);
|
||||
|
||||
discoveryState = DISC_ANCS_CHAR;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Service not found
|
||||
discoveryState = DISC_FAILED;
|
||||
PRINT("ANCS SVC not present\n");
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case DISC_ANCS_CHAR:
|
||||
{
|
||||
// Characteristics found, chache them
|
||||
uint8_t *pHandleValuePairList;
|
||||
uint16_t handle;
|
||||
uint16_t uuid;
|
||||
if (pMsg->method == ATT_READ_BY_TYPE_RSP &&
|
||||
pMsg->msg.readByTypeRsp.numPairs > 0 &&
|
||||
pMsg->msg.readByTypeRsp.len == CHAR_DESC_HDL_UUID128_LEN)
|
||||
{
|
||||
pHandleValuePairList = pMsg->msg.readByTypeRsp.pDataList;
|
||||
uint8_t i;
|
||||
// For each handle value pair in the list of chars in ANCS service
|
||||
for (i = pMsg->msg.readByTypeRsp.numPairs; i > 0; i--)
|
||||
{
|
||||
// Parse characteristic declaration
|
||||
handle = BUILD_UINT16(pHandleValuePairList[3],
|
||||
pHandleValuePairList[4]);
|
||||
uuid = BUILD_UINT16(pHandleValuePairList[5],
|
||||
pHandleValuePairList[6]);
|
||||
|
||||
// If looking for end handle
|
||||
if (Ancs_endHdlIdx != 0)
|
||||
{
|
||||
// End handle is characteristic declaration handle - 1
|
||||
Ancs_handleCache[Ancs_endHdlIdx] =
|
||||
BUILD_UINT16(pHandleValuePairList[0],
|
||||
pHandleValuePairList[1]) - 1;
|
||||
|
||||
Ancs_endHdlIdx = 0;
|
||||
}
|
||||
|
||||
// If UUID is of interest, cache handle
|
||||
switch (uuid)
|
||||
{
|
||||
case ANCS_NOTIF_SRC_CHAR_UUID:
|
||||
ancs_c.handle_ns = handle;
|
||||
Ancs_handleCache[HDL_ANCS_NTF_NOTIF_START] = handle;
|
||||
Ancs_endHdlIdx = HDL_ANCS_NTF_NOTIF_END;
|
||||
break;
|
||||
|
||||
case ANCS_CTRL_PT_CHAR_UUID:
|
||||
ancs_c.handle_cp = handle;
|
||||
Ancs_handleCache[HDL_ANCS_CTRL_PT_START] = handle;
|
||||
Ancs_endHdlIdx = HDL_ANCS_CTRL_PT_END;
|
||||
break;
|
||||
|
||||
case ANCS_DATA_SRC_CHAR_UUID:
|
||||
ancs_c.handle_ds = handle;
|
||||
Ancs_handleCache[HDL_ANCS_DATA_SRC_START] = handle;
|
||||
Ancs_endHdlIdx = HDL_ANCS_DATA_SRC_END;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
pHandleValuePairList += CHAR_DESC_HDL_UUID128_LEN;
|
||||
}
|
||||
}
|
||||
|
||||
// If procedure complete
|
||||
if ((pMsg->method == ATT_READ_BY_TYPE_RSP &&
|
||||
pMsg->hdr.status == bleProcedureComplete) ||
|
||||
(pMsg->method == ATT_ERROR_RSP))
|
||||
{
|
||||
// Special case of end handle at end of service
|
||||
if (Ancs_endHdlIdx != 0)
|
||||
{
|
||||
Ancs_handleCache[Ancs_endHdlIdx] = Ancs_svcEndHdl;
|
||||
Ancs_endHdlIdx = 0;
|
||||
}
|
||||
|
||||
// If notification source char is missing, there is something wrong
|
||||
if (Ancs_handleCache[HDL_ANCS_NTF_NOTIF_START] == 0)
|
||||
{
|
||||
PRINT("Notif src not found\n");
|
||||
discoveryState = DISC_FAILED;
|
||||
}
|
||||
else if (Ancs_handleCache[HDL_ANCS_NTF_NOTIF_START] <
|
||||
Ancs_handleCache[HDL_ANCS_NTF_NOTIF_END])
|
||||
{
|
||||
// Discover ANCS Notification Source CCCD
|
||||
GATT_DiscAllCharDescs(pMsg->connHandle,
|
||||
Ancs_handleCache[HDL_ANCS_NTF_NOTIF_START] + 1,
|
||||
Ancs_handleCache[HDL_ANCS_NTF_NOTIF_END],
|
||||
ancs_taskid);
|
||||
isNotifCCCD = TRUE;
|
||||
discoveryState = DISC_ANCS_CCCD;
|
||||
}
|
||||
else
|
||||
{
|
||||
PRINT("CCCD missing\n");
|
||||
// Missing required characteristic descriptor
|
||||
Ancs_handleCache[HDL_ANCS_NTF_NOTIF_START] = 0;
|
||||
discoveryState = DISC_FAILED;
|
||||
}
|
||||
}
|
||||
// Discover all characteristics of ANCS service until end handle
|
||||
else
|
||||
{
|
||||
GATT_DiscAllChars(pMsg->connHandle, handle+1,
|
||||
Ancs_svcEndHdl, ancs_taskid);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case DISC_ANCS_CCCD:
|
||||
{
|
||||
// Characteristic descriptors found
|
||||
if (pMsg->method == ATT_FIND_INFO_RSP &&
|
||||
pMsg->msg.findInfoRsp.numInfo > 0 &&
|
||||
pMsg->msg.findInfoRsp.format == 0x01)
|
||||
{
|
||||
uint8_t i;
|
||||
// For each handle/uuid pair
|
||||
for (i = 0; i < pMsg->msg.findInfoRsp.numInfo; i++)
|
||||
{
|
||||
// Look for CCCD
|
||||
if (ATT_BT_PAIR_UUID(pMsg->msg.findInfoRsp.pInfo, i) ==
|
||||
GATT_CLIENT_CHAR_CFG_UUID)
|
||||
{
|
||||
// CCCD found
|
||||
// if it is Notification Source CCCD
|
||||
if (isNotifCCCD == TRUE)
|
||||
{
|
||||
ancs_c.handle_ns_ccc =
|
||||
ATT_BT_PAIR_HANDLE(pMsg->msg.findInfoRsp.pInfo, i);
|
||||
Ancs_handleCache[HDL_ANCS_NTF_CCCD] =
|
||||
ATT_BT_PAIR_HANDLE(pMsg->msg.findInfoRsp.pInfo, i);
|
||||
}
|
||||
// else it is Data Source CCCD
|
||||
else
|
||||
{
|
||||
ancs_c.handle_ds_ccc =
|
||||
ATT_BT_PAIR_HANDLE(pMsg->msg.findInfoRsp.pInfo, i);
|
||||
Ancs_handleCache[HDL_ANCS_DATA_SRC_CCCD] =
|
||||
ATT_BT_PAIR_HANDLE(pMsg->msg.findInfoRsp.pInfo, i);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If procedure complete
|
||||
if ((pMsg->method == ATT_FIND_INFO_RSP &&
|
||||
pMsg->hdr.status == bleProcedureComplete) ||
|
||||
(pMsg->method == ATT_ERROR_RSP))
|
||||
{
|
||||
// Discover ANCS Data Source characteristic descriptors
|
||||
if (isNotifCCCD == TRUE &&
|
||||
Ancs_handleCache[HDL_ANCS_DATA_SRC_CCCD] == 0)
|
||||
{
|
||||
GATT_DiscAllCharDescs(pMsg->connHandle,
|
||||
Ancs_handleCache[HDL_ANCS_DATA_SRC_START] + 1,
|
||||
Ancs_handleCache[HDL_ANCS_DATA_SRC_END],
|
||||
ancs_taskid);
|
||||
|
||||
isNotifCCCD = FALSE;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
discoveryState = DISC_IDLE;
|
||||
atomic_set_bit(&ancs_c.state, ANCS_BT_DISCOVERY_COMPLETE);
|
||||
PRINT("discover complete\n");
|
||||
tmos_set_event(ancs_taskid, START_SUBSCRIPE_NOTIDATA_EVT);
|
||||
tmos_set_event(ancs_taskid, START_SUBSCRIPE_NOTISRC_EVT);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/************************ endfile @ central **************************/
|
||||
@@ -0,0 +1,74 @@
|
||||
/********************************** (C) COPYRIGHT *******************************
|
||||
* File Name : ch32v20x_it.c
|
||||
* Author : WCH
|
||||
* Version : V1.0.0
|
||||
* Date : 2022/06/16
|
||||
* Description : Main Interrupt Service Routines.
|
||||
*********************************************************************************
|
||||
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
|
||||
* Attention: This software (modified or not) and binary are used for
|
||||
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
|
||||
*******************************************************************************/
|
||||
|
||||
/*********************************************************************
|
||||
* INCLUDES
|
||||
*/
|
||||
#include "ch32v20x_it.h"
|
||||
#include "CONFIG.h"
|
||||
|
||||
/*********************************************************************
|
||||
* LOCAL FUNCTIONS
|
||||
*/
|
||||
void NMI_Handler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
|
||||
void HardFault_Handler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
|
||||
void BB_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
|
||||
void LLE_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
|
||||
|
||||
/*********************************************************************
|
||||
* @fn NMI_Handler
|
||||
*
|
||||
* @brief This function handles NMI exception.
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
void NMI_Handler(void)
|
||||
{
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* @fn HardFault_Handler
|
||||
*
|
||||
* @brief This function handles Hard Fault exception.
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
void HardFault_Handler(void)
|
||||
{
|
||||
while(1)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* @fn BB_IRQHandler
|
||||
*
|
||||
* @brief BB Interrupt for BLE.
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
void BB_IRQHandler(void)
|
||||
{
|
||||
BB_IRQLibHandler();
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* @fn LLE_IRQHandler
|
||||
*
|
||||
* @brief LLE Interrupt for BLE.
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
void LLE_IRQHandler(void)
|
||||
{
|
||||
LLE_IRQLibHandler();
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
|
||||
*
|
||||
* Attention: This software (modified or not) and binary are used for
|
||||
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
|
||||
*/
|
||||
|
||||
#ifndef ANCS_H
|
||||
#define ANCS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/*********************************************************************
|
||||
* INCLUDES
|
||||
*/
|
||||
#include "config.h"
|
||||
#include "ancs_client.h"
|
||||
#include <stdint.h>
|
||||
/*********************************************************************
|
||||
* CONSTANTS
|
||||
*/
|
||||
|
||||
// ANCS discovery states
|
||||
enum
|
||||
{
|
||||
DISC_IDLE = 0x00, // Idle state
|
||||
|
||||
DISC_ANCS_START = 0x10, // ANCS service
|
||||
DISC_ANCS_SVC, // Discover service
|
||||
DISC_ANCS_CHAR, // Discover all characteristics
|
||||
DISC_ANCS_CCCD, // Discover ANCS CCCD
|
||||
|
||||
DISC_FAILED = 0xFF // Discovery failed
|
||||
};
|
||||
|
||||
// ANCS handle cache indexes
|
||||
enum
|
||||
{
|
||||
HDL_ANCS_NTF_NOTIF_START, // ANCS notification characteristic start handle
|
||||
HDL_ANCS_NTF_NOTIF_END, // ANCS notification characteristic end handle
|
||||
HDL_ANCS_NTF_CCCD, // ANCS notification CCCD
|
||||
|
||||
HDL_ANCS_CTRL_PT_START,
|
||||
HDL_ANCS_CTRL_PT_END,
|
||||
|
||||
HDL_ANCS_DATA_SRC_START, // ANCS data source characteristic start handle
|
||||
HDL_ANCS_DATA_SRC_END, // ANCS data source characteristic end handle
|
||||
HDL_ANCS_DATA_SRC_CCCD, // ANCS data source CCCD
|
||||
|
||||
|
||||
HDL_CACHE_LEN
|
||||
};
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
* TYPEDEFS
|
||||
*/
|
||||
|
||||
struct bt_ancs_subscribe_cb {
|
||||
void(*notification_source)(struct bt_ancs_client *ancs_c,
|
||||
int err, const struct bt_ancs_evt_notif *notif);
|
||||
void(*data_source)(struct bt_ancs_client *ancs_c,
|
||||
const struct bt_ancs_attr_response *response);
|
||||
void(*write_response)(struct bt_ancs_client *ancs_c,
|
||||
uint8_t err);
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint16_t connHandle; // Connection handle of current connection
|
||||
uint16_t connInterval;
|
||||
uint16_t connSlaveLatency;
|
||||
uint16_t connTimeout;
|
||||
} peripheralConnItem_t;
|
||||
|
||||
/*********************************************************************
|
||||
* MACROS
|
||||
*/
|
||||
|
||||
#define START_DEVICE_EVT 0x0001
|
||||
#define START_SUBSCRIPE_NOTISRC_EVT 0x0002
|
||||
#define START_SUBSCRIPE_NOTIDATA_EVT 0x0004
|
||||
#define START_DISCOVER_EVT 0x0008
|
||||
#define START_PARAM_UPDATE_EVT 0x0010
|
||||
#define START_PHY_UPDATE_EVT 0x0020
|
||||
|
||||
// Handle and 16-bit Bluetooth UUID pair indexes
|
||||
#define ATT_BT_PAIR_HANDLE_IDX( i ) ( (i) * (2 + ATT_BT_UUID_SIZE) )
|
||||
#define ATT_BT_PAIR_UUID_IDX( i ) ( ATT_BT_PAIR_HANDLE_IDX( (i) ) + 2 )
|
||||
|
||||
#define ATT_BT_PAIR_HANDLE( info, i ) ( BUILD_UINT16( (info)[ATT_BT_PAIR_HANDLE_IDX((i))], \
|
||||
(info)[ATT_BT_PAIR_HANDLE_IDX((i))+1] ) )
|
||||
#define ATT_BT_PAIR_UUID( info, i ) ( BUILD_UINT16( (info)[ATT_BT_PAIR_UUID_IDX((i))], \
|
||||
(info)[ATT_BT_PAIR_UUID_IDX((i))+1] ) )
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
* GLOBAL
|
||||
*/
|
||||
enum
|
||||
{
|
||||
CCCD_CONFIG_NOTIF = 0x00,
|
||||
CCCD_CONFIG_DATA,
|
||||
CCCD_CONFIG_DONE
|
||||
};
|
||||
|
||||
extern struct bt_ancs_client ancs_c;
|
||||
|
||||
extern uint8_t ancs_taskid;
|
||||
|
||||
// Handle cache
|
||||
extern uint16_t Ancs_handleCache[HDL_CACHE_LEN];
|
||||
|
||||
/*********************************************************************
|
||||
* FUNCTIONS
|
||||
*/
|
||||
|
||||
/*
|
||||
* ANCS service discovery functions.
|
||||
*/
|
||||
void peripheral_ancs_client_init(void);
|
||||
|
||||
void ancs_subscribe_cb_register(struct bt_ancs_subscribe_cb *cb);
|
||||
|
||||
/*********************************************************************
|
||||
*********************************************************************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ANCS_H */
|
||||
@@ -0,0 +1,37 @@
|
||||
/********************************** (C) COPYRIGHT *******************************
|
||||
* File Name : ch32v20x_conf.h
|
||||
* Author : WCH
|
||||
* Version : V1.0.0
|
||||
* Date : 2022/06/16
|
||||
* Description : Library configuration file.
|
||||
*********************************************************************************
|
||||
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
|
||||
* Attention: This software (modified or not) and binary are used for
|
||||
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __CH32V20x_CONF_H
|
||||
#define __CH32V20x_CONF_H
|
||||
|
||||
#include "ch32v20x_adc.h"
|
||||
#include "ch32v20x_bkp.h"
|
||||
#include "ch32v20x_can.h"
|
||||
#include "ch32v20x_crc.h"
|
||||
#include "ch32v20x_dbgmcu.h"
|
||||
#include "ch32v20x_dma.h"
|
||||
#include "ch32v20x_exti.h"
|
||||
#include "ch32v20x_flash.h"
|
||||
#include "ch32v20x_gpio.h"
|
||||
#include "ch32v20x_i2c.h"
|
||||
#include "ch32v20x_iwdg.h"
|
||||
#include "ch32v20x_pwr.h"
|
||||
#include "ch32v20x_rcc.h"
|
||||
#include "ch32v20x_rtc.h"
|
||||
#include "ch32v20x_spi.h"
|
||||
#include "ch32v20x_tim.h"
|
||||
#include "ch32v20x_usart.h"
|
||||
#include "ch32v20x_wwdg.h"
|
||||
#include "ch32v20x_it.h"
|
||||
#include "ch32v20x_misc.h"
|
||||
|
||||
#endif /* __CH32V20x_CONF_H */
|
||||
@@ -0,0 +1,18 @@
|
||||
/********************************** (C) COPYRIGHT *******************************
|
||||
* File Name : ch32v20x_it.h
|
||||
* Author : WCH
|
||||
* Version : V1.0.0
|
||||
* Date : 2022/06/16
|
||||
* Description : This file contains the headers of the interrupt handlers.
|
||||
*********************************************************************************
|
||||
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
|
||||
* Attention: This software (modified or not) and binary are used for
|
||||
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __CH32V20x_IT_H
|
||||
#define __CH32V20x_IT_H
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
#endif /* __CH32V20x_IT_H */
|
||||
@@ -0,0 +1,31 @@
|
||||
/********************************** (C) COPYRIGHT *******************************
|
||||
* File Name : system_ch32v20x.h
|
||||
* Author : WCH
|
||||
* Version : V1.0.0
|
||||
* Date : 2022/06/16
|
||||
* Description : CH32V20x Device Peripheral Access Layer System Header File.
|
||||
*********************************************************************************
|
||||
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
|
||||
* Attention: This software (modified or not) and binary are used for
|
||||
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __SYSTEM_ch32v20x_H
|
||||
#define __SYSTEM_ch32v20x_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern uint32_t SystemCoreClock; /* System Clock Frequency (Core Clock) */
|
||||
|
||||
/* System_Exported_Functions */
|
||||
extern void SystemInit(void);
|
||||
extern void SystemCoreClockUpdate(void);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /*__CH32V20x_SYSTEM_H */
|
||||
@@ -0,0 +1,32 @@
|
||||
#ifndef TIME_UNITS_H
|
||||
#define TIME_UNITS_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifdef CLK_OSC32K
|
||||
#if (CLK_OSC32K==1)
|
||||
#define FREQ_RTC 32000
|
||||
#else
|
||||
#define FREQ_RTC 32768
|
||||
#endif
|
||||
#endif /* CLK_OSC32K */
|
||||
|
||||
|
||||
#define CLK_PER_US (1.0 / ((1.0 / FREQ_RTC) * 1000 * 1000)) // 0.032 clk/us
|
||||
#define CLK_PER_MS (CLK_PER_US * 1000) // 32clk/ms
|
||||
|
||||
#define US_PER_CLK (1.0 / CLK_PER_US) // 31.25us/clk
|
||||
#define MS_PER_CLK (US_PER_CLK / 1000.0) // 0.03125ms/clk
|
||||
|
||||
#define SYS_TO_US(clk) ((uint32_t)((clk) * US_PER_CLK))
|
||||
#define SYS_TO_MS(clk) ((uint32_t)((clk) * MS_PER_CLK))
|
||||
|
||||
#define US_TO_SYS(us) ((uint32_t)((us) * CLK_PER_US))
|
||||
#define MS_TO_SYS(ms) ((uint32_t)((ms) * CLK_PER_MS ))
|
||||
|
||||
static inline uint32_t get_current_time(void)
|
||||
{
|
||||
return SYS_TO_MS(RTC_GetCounter());
|
||||
}
|
||||
|
||||
#endif /* TIME_UNITS_H */
|
||||
@@ -0,0 +1,413 @@
|
||||
/********************************** (C) COPYRIGHT *******************************
|
||||
* File Name : main.c
|
||||
* Author : WCH
|
||||
* Version : V1.1
|
||||
* Date : 2020/08/06
|
||||
* Description :
|
||||
*********************************************************************************
|
||||
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
|
||||
* Attention: This software (modified or not) and binary are used for
|
||||
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
|
||||
*******************************************************************************/
|
||||
|
||||
/******************************************************************************/
|
||||
#include <time_units.h>
|
||||
#include "CONFIG.h"
|
||||
#include "HAL.h"
|
||||
#include "ancs.h"
|
||||
#include "ancs_client.h"
|
||||
#include "time_units.h"
|
||||
|
||||
|
||||
static void bt_ancs_notification_source_handler(struct bt_ancs_client *ancs_c,
|
||||
int err, const struct bt_ancs_evt_notif *notif);
|
||||
static void bt_ancs_data_source_handler(struct bt_ancs_client *ancs_c,
|
||||
const struct bt_ancs_attr_response *response);
|
||||
static void bt_ancs_write_response_handler(struct bt_ancs_client *ancs_c,
|
||||
uint8_t err);
|
||||
|
||||
__attribute__((aligned(4))) uint32_t MEM_BUF[BLE_MEMHEAP_SIZE / 4];
|
||||
|
||||
#if(defined(BLE_MAC)) && (BLE_MAC == TRUE)
|
||||
const uint8_t MacAddr[6] = {0x84, 0xC2, 0xE4, 0x03, 0x02, 0x02};
|
||||
#endif
|
||||
|
||||
#define ATTR_DATA_SIZE BT_ANCS_ATTR_DATA_MAX
|
||||
|
||||
#define KEY_REQ_NOTI_ATTR (1<<0)
|
||||
#define KEY_REQ_APP_ATTR (1<<1)
|
||||
#define KEY_POS_ACTION (1<<0)
|
||||
#define KEY_NEG_ACTION (1<<0)
|
||||
|
||||
static struct bt_ancs_subscribe_cb subscribe = {
|
||||
.data_source = bt_ancs_data_source_handler,
|
||||
.notification_source = bt_ancs_notification_source_handler,
|
||||
.write_response = bt_ancs_write_response_handler,
|
||||
};
|
||||
|
||||
|
||||
/* Local copy to keep track of the newest arriving notifications. */
|
||||
static struct bt_ancs_evt_notif notification_latest;
|
||||
/* Local copy of the newest notification attribute. */
|
||||
static struct bt_ancs_attr notif_attr_latest;
|
||||
/* Local copy of the newest app attribute. */
|
||||
static struct bt_ancs_attr notif_attr_app_id_latest;
|
||||
|
||||
/* Buffers to store attribute data. */
|
||||
static uint8_t attr_appid[ATTR_DATA_SIZE];
|
||||
static uint8_t attr_title[ATTR_DATA_SIZE];
|
||||
static uint8_t attr_subtitle[ATTR_DATA_SIZE];
|
||||
static uint8_t attr_message[ATTR_DATA_SIZE];
|
||||
static uint8_t attr_message_size[ATTR_DATA_SIZE];
|
||||
static uint8_t attr_date[ATTR_DATA_SIZE];
|
||||
static uint8_t attr_posaction[ATTR_DATA_SIZE];
|
||||
static uint8_t attr_negaction[ATTR_DATA_SIZE];
|
||||
static uint8_t attr_disp_name[ATTR_DATA_SIZE];
|
||||
|
||||
/* String literals for the iOS notification categories.
|
||||
* Used then printing to UART.
|
||||
*/
|
||||
static const char *lit_catid[BT_ANCS_CATEGORY_ID_COUNT] = {
|
||||
"Other",
|
||||
"Incoming Call",
|
||||
"Missed Call",
|
||||
"Voice Mail",
|
||||
"Social",
|
||||
"Schedule",
|
||||
"Email",
|
||||
"News",
|
||||
"Health And Fitness",
|
||||
"Business And Finance",
|
||||
"Location",
|
||||
"Entertainment"
|
||||
};
|
||||
|
||||
/* String literals for the iOS notification event types.
|
||||
* Used then printing to UART.
|
||||
*/
|
||||
static const char *lit_eventid[BT_ANCS_EVT_ID_COUNT] = { "Added",
|
||||
"Modified",
|
||||
"Removed" };
|
||||
|
||||
/* String literals for the iOS notification attribute types.
|
||||
* Used when printing to UART.
|
||||
*/
|
||||
static const char *lit_attrid[BT_ANCS_NOTIF_ATTR_COUNT] = {
|
||||
"App Identifier",
|
||||
"Title",
|
||||
"Subtitle",
|
||||
"Message",
|
||||
"Message Size",
|
||||
"Date",
|
||||
"Positive Action Label",
|
||||
"Negative Action Label"
|
||||
};
|
||||
|
||||
static const char *lit_appid[BT_ANCS_APP_ATTR_COUNT] = { "Display Name" };
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static void notif_print(struct bt_ancs_evt_notif *notif)
|
||||
{
|
||||
PRINT("\nNotification\n");
|
||||
PRINT("Event: %s\n", lit_eventid[notif->evt_id]);
|
||||
PRINT("Category ID: %s\n", lit_catid[notif->category_id]);
|
||||
PRINT("Category Cnt:%u\n", (unsigned int)notif->category_count);
|
||||
PRINT("UID: %u\n", (unsigned int)notif->notif_uid);
|
||||
|
||||
PRINT("Flags:\n");
|
||||
if (notif->evt_flags.silent) {
|
||||
PRINT(" Silent\n");
|
||||
}
|
||||
if (notif->evt_flags.important) {
|
||||
PRINT(" Important\n");
|
||||
}
|
||||
if (notif->evt_flags.pre_existing) {
|
||||
PRINT(" Pre-existing\n");
|
||||
}
|
||||
if (notif->evt_flags.positive_action) {
|
||||
PRINT(" Positive Action\n");
|
||||
}
|
||||
if (notif->evt_flags.negative_action) {
|
||||
PRINT(" Negative Action\n");
|
||||
}
|
||||
}
|
||||
|
||||
/**@brief Function for printing iOS notification attribute data.
|
||||
*
|
||||
* @param[in] attr Pointer to an iOS notification attribute.
|
||||
*/
|
||||
static void notif_attr_print(const struct bt_ancs_attr *attr)
|
||||
{
|
||||
if (attr->attr_len != 0) {
|
||||
PRINT("%s: %s\n", lit_attrid[attr->attr_id],
|
||||
(char *)attr->attr_data);
|
||||
} else if (attr->attr_len == 0) {
|
||||
PRINT("%s: (N/A)\n", lit_attrid[attr->attr_id]);
|
||||
}
|
||||
}
|
||||
|
||||
/**@brief Function for printing iOS notification attribute data.
|
||||
*
|
||||
* @param[in] attr Pointer to an iOS App attribute.
|
||||
*/
|
||||
static void app_attr_print(const struct bt_ancs_attr *attr)
|
||||
{
|
||||
if (attr->attr_len != 0) {
|
||||
PRINT("%s: %s\n", lit_appid[attr->attr_id],
|
||||
(char *)attr->attr_data);
|
||||
} else if (attr->attr_len == 0) {
|
||||
PRINT("%s: (N/A)\n", lit_appid[attr->attr_id]);
|
||||
}
|
||||
}
|
||||
|
||||
static int ancs_init(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = bt_ancs_client_init(&ancs_c);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
err = bt_ancs_register_attr(&ancs_c,
|
||||
BT_ANCS_NOTIF_ATTR_ID_APP_IDENTIFIER,
|
||||
attr_appid, ATTR_DATA_SIZE);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
err = bt_ancs_register_app_attr(&ancs_c,
|
||||
BT_ANCS_APP_ATTR_ID_DISPLAY_NAME,
|
||||
attr_disp_name, sizeof(attr_disp_name));
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
err = bt_ancs_register_attr(&ancs_c,
|
||||
BT_ANCS_NOTIF_ATTR_ID_TITLE,
|
||||
attr_title, ATTR_DATA_SIZE);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
err = bt_ancs_register_attr(&ancs_c,
|
||||
BT_ANCS_NOTIF_ATTR_ID_MESSAGE,
|
||||
attr_message, ATTR_DATA_SIZE);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
err = bt_ancs_register_attr(&ancs_c,
|
||||
BT_ANCS_NOTIF_ATTR_ID_SUBTITLE,
|
||||
attr_subtitle, ATTR_DATA_SIZE);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
err = bt_ancs_register_attr(&ancs_c,
|
||||
BT_ANCS_NOTIF_ATTR_ID_MESSAGE_SIZE,
|
||||
attr_message_size, ATTR_DATA_SIZE);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
err = bt_ancs_register_attr(&ancs_c,
|
||||
BT_ANCS_NOTIF_ATTR_ID_DATE,
|
||||
attr_date, ATTR_DATA_SIZE);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
err = bt_ancs_register_attr(&ancs_c,
|
||||
BT_ANCS_NOTIF_ATTR_ID_POSITIVE_ACTION_LABEL,
|
||||
attr_posaction, ATTR_DATA_SIZE);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
err = bt_ancs_register_attr(&ancs_c,
|
||||
BT_ANCS_NOTIF_ATTR_ID_NEGATIVE_ACTION_LABEL,
|
||||
attr_negaction, ATTR_DATA_SIZE);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void bt_ancs_notification_source_handler(struct bt_ancs_client *ancs_c,
|
||||
int err, const struct bt_ancs_evt_notif *notif)
|
||||
{
|
||||
if (!err) {
|
||||
notification_latest = *notif;
|
||||
notif_print(¬ification_latest);
|
||||
}
|
||||
}
|
||||
|
||||
static void bt_ancs_data_source_handler(struct bt_ancs_client *ancs_c,
|
||||
const struct bt_ancs_attr_response *response)
|
||||
{
|
||||
switch (response->command_id) {
|
||||
case BT_ANCS_COMMAND_ID_GET_NOTIF_ATTRIBUTES:
|
||||
notif_attr_latest = response->attr;
|
||||
notif_attr_print(¬if_attr_latest);
|
||||
if (response->attr.attr_id ==
|
||||
BT_ANCS_NOTIF_ATTR_ID_APP_IDENTIFIER) {
|
||||
notif_attr_app_id_latest = response->attr;
|
||||
}
|
||||
break;
|
||||
|
||||
case BT_ANCS_COMMAND_ID_GET_APP_ATTRIBUTES:
|
||||
app_attr_print(&response->attr);
|
||||
break;
|
||||
|
||||
default:
|
||||
/* No implementation needed. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void bt_ancs_write_response_handler(struct bt_ancs_client *ancs_c,
|
||||
uint8_t err)
|
||||
{
|
||||
switch (err) {
|
||||
case BT_ATT_ERR_ANCS_NP_UNKNOWN_COMMAND:
|
||||
PRINT("Error: Command ID was not recognized by the Notification Provider.\n");
|
||||
break;
|
||||
|
||||
case BT_ATT_ERR_ANCS_NP_INVALID_COMMAND:
|
||||
PRINT("Error: Command failed to be parsed on the Notification Provider.\n");
|
||||
break;
|
||||
|
||||
case BT_ATT_ERR_ANCS_NP_INVALID_PARAMETER:
|
||||
PRINT("Error: Parameter does not refer to an existing object on the Notification Provider.\n");
|
||||
break;
|
||||
|
||||
case BT_ATT_ERR_ANCS_NP_ACTION_FAILED:
|
||||
PRINT("Error: Perform Notification Action Failed on the Notification Provider.\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
struct key_state {
|
||||
uint32_t timestamp_key1;
|
||||
uint32_t timestamp_key2;
|
||||
};
|
||||
|
||||
/**
|
||||
* key1(PB22):
|
||||
* single: request attributes for a notification.
|
||||
* double: request attributes for a given app.
|
||||
*
|
||||
* key2(PB4):
|
||||
* single: perform a positive action.
|
||||
* double: perform a negative action.
|
||||
*/
|
||||
void button_changed(uint8_t keys)
|
||||
{
|
||||
int err;
|
||||
static struct key_state k_s = {0};
|
||||
|
||||
if(keys & HAL_KEY_SW_1){
|
||||
uint32_t current_time = get_current_time();
|
||||
if(current_time - k_s.timestamp_key1 < 600){
|
||||
if (notif_attr_app_id_latest.attr_id ==
|
||||
BT_ANCS_NOTIF_ATTR_ID_APP_IDENTIFIER &&
|
||||
notif_attr_app_id_latest.attr_len != 0) {
|
||||
PRINT("Request for %s:\n",
|
||||
notif_attr_app_id_latest.attr_data);
|
||||
err = bt_ancs_request_app_attr(
|
||||
&ancs_c, notif_attr_app_id_latest.attr_data,
|
||||
notif_attr_app_id_latest.attr_len,
|
||||
bt_ancs_write_response_handler);
|
||||
if (err) {
|
||||
PRINT("Failed requesting attributes for a given app (err: %d)\n",
|
||||
err);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
err = bt_ancs_request_attrs(&ancs_c, ¬ification_latest,
|
||||
bt_ancs_write_response_handler);
|
||||
if(err){
|
||||
PRINT("Failed requesting attributes for a notification (err: %d)\n",
|
||||
err);
|
||||
}
|
||||
}
|
||||
k_s.timestamp_key1 = current_time;
|
||||
}
|
||||
|
||||
if(keys & HAL_KEY_SW_2){
|
||||
uint32_t current_time = get_current_time();
|
||||
if(current_time - k_s.timestamp_key2 < 600){
|
||||
PRINT("Performing Negative Action.\n");
|
||||
err = bt_ancs_notification_action(
|
||||
&ancs_c, notification_latest.notif_uid,
|
||||
BT_ANCS_ACTION_ID_NEGATIVE,
|
||||
bt_ancs_write_response_handler);
|
||||
if (err) {
|
||||
PRINT("Failed performing action (err: %d)\n",
|
||||
err);
|
||||
}
|
||||
} else {
|
||||
PRINT("Performing Positive Action.\n");
|
||||
err = bt_ancs_notification_action(
|
||||
&ancs_c, notification_latest.notif_uid,
|
||||
BT_ANCS_ACTION_ID_POSITIVE,
|
||||
bt_ancs_write_response_handler);
|
||||
if (err) {
|
||||
PRINT("Failed performing action (err: %d)\n",
|
||||
err);
|
||||
}
|
||||
}
|
||||
|
||||
k_s.timestamp_key2 = current_time;
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* @fn Main_Circulation
|
||||
*
|
||||
* @brief Main loop
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
__attribute__((section(".highcode")))
|
||||
__attribute__((noinline))
|
||||
void Main_Circulation(void)
|
||||
{
|
||||
while(1)
|
||||
{
|
||||
TMOS_SystemProcess();
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* @fn main
|
||||
*
|
||||
* @brief Main function
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
int main(void)
|
||||
{
|
||||
Delay_Init();
|
||||
#ifdef DEBUG
|
||||
USART_Printf_Init( 115200 );
|
||||
#endif
|
||||
PRINT("start.%s\n",__TIME__);
|
||||
PRINT("%s\n", VER_LIB);
|
||||
WCHBLE_Init();
|
||||
HAL_Init();
|
||||
|
||||
HalKeyConfig(button_changed);
|
||||
ancs_init();
|
||||
ancs_subscribe_cb_register(&subscribe);
|
||||
GAPRole_PeripheralInit();
|
||||
peripheral_ancs_client_init();
|
||||
Main_Circulation();
|
||||
}
|
||||
|
||||
/******************************** endfile @ main ******************************/
|
||||
@@ -0,0 +1,989 @@
|
||||
/********************************** (C) COPYRIGHT *******************************
|
||||
* File Name : system_ch32v20x.c
|
||||
* Author : WCH
|
||||
* Version : V1.0.0
|
||||
* Date : 2021/06/06
|
||||
* Description : CH32V20x Device Peripheral Access Layer System Source File.
|
||||
* For HSE = 32Mhz (CH32V208x/CH32V203RBT6)
|
||||
* For HSE = 8Mhz (other CH32V203x)
|
||||
*********************************************************************************
|
||||
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
|
||||
* Attention: This software (modified or not) and binary are used for
|
||||
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
|
||||
*******************************************************************************/
|
||||
#include "ch32v20x.h"
|
||||
|
||||
/*
|
||||
* Uncomment the line corresponding to the desired System clock (SYSCLK) frequency (after
|
||||
* reset the HSI is used as SYSCLK source).
|
||||
* If none of the define below is enabled, the HSI is used as System clock source.
|
||||
*/
|
||||
//#define SYSCLK_FREQ_HSE HSE_VALUE
|
||||
//#define SYSCLK_FREQ_48MHz_HSE 48000000
|
||||
//#define SYSCLK_FREQ_56MHz_HSE 56000000
|
||||
//#define SYSCLK_FREQ_72MHz_HSE 72000000
|
||||
#define SYSCLK_FREQ_96MHz_HSE 96000000
|
||||
//#define SYSCLK_FREQ_120MHz_HSE 120000000
|
||||
//#define SYSCLK_FREQ_144MHz_HSE 144000000
|
||||
//#define SYSCLK_FREQ_HSI HSI_VALUE
|
||||
//#define SYSCLK_FREQ_48MHz_HSI 48000000
|
||||
//#define SYSCLK_FREQ_56MHz_HSI 56000000
|
||||
//#define SYSCLK_FREQ_72MHz_HSI 72000000
|
||||
//#define SYSCLK_FREQ_96MHz_HSI 96000000
|
||||
//#define SYSCLK_FREQ_120MHz_HSI 120000000
|
||||
//#define SYSCLK_FREQ_144MHz_HSI 144000000
|
||||
|
||||
/* Clock Definitions */
|
||||
#ifdef SYSCLK_FREQ_HSE
|
||||
uint32_t SystemCoreClock = SYSCLK_FREQ_HSE; /* System Clock Frequency (Core Clock) */
|
||||
#elif defined SYSCLK_FREQ_48MHz_HSE
|
||||
uint32_t SystemCoreClock = SYSCLK_FREQ_48MHz_HSE; /* System Clock Frequency (Core Clock) */
|
||||
#elif defined SYSCLK_FREQ_56MHz_HSE
|
||||
uint32_t SystemCoreClock = SYSCLK_FREQ_56MHz_HSE; /* System Clock Frequency (Core Clock) */
|
||||
#elif defined SYSCLK_FREQ_72MHz_HSE
|
||||
uint32_t SystemCoreClock = SYSCLK_FREQ_72MHz_HSE; /* System Clock Frequency (Core Clock) */
|
||||
#elif defined SYSCLK_FREQ_96MHz_HSE
|
||||
uint32_t SystemCoreClock = SYSCLK_FREQ_96MHz_HSE; /* System Clock Frequency (Core Clock) */
|
||||
#elif defined SYSCLK_FREQ_120MHz_HSE
|
||||
uint32_t SystemCoreClock = SYSCLK_FREQ_120MHz_HSE; /* System Clock Frequency (Core Clock) */
|
||||
#elif defined SYSCLK_FREQ_144MHz_HSE
|
||||
uint32_t SystemCoreClock = SYSCLK_FREQ_144MHz_HSE; /* System Clock Frequency (Core Clock) */
|
||||
#elif defined SYSCLK_FREQ_48MHz_HSI
|
||||
uint32_t SystemCoreClock = SYSCLK_FREQ_48MHz_HSI; /* System Clock Frequency (Core Clock) */
|
||||
#elif defined SYSCLK_FREQ_56MHz_HSI
|
||||
uint32_t SystemCoreClock = SYSCLK_FREQ_56MHz_HSI; /* System Clock Frequency (Core Clock) */
|
||||
#elif defined SYSCLK_FREQ_72MHz_HSI
|
||||
uint32_t SystemCoreClock = SYSCLK_FREQ_72MHz_HSI; /* System Clock Frequency (Core Clock) */
|
||||
#elif defined SYSCLK_FREQ_96MHz_HSI
|
||||
uint32_t SystemCoreClock = SYSCLK_FREQ_96MHz_HSI; /* System Clock Frequency (Core Clock) */
|
||||
#elif defined SYSCLK_FREQ_120MHz_HSI
|
||||
uint32_t SystemCoreClock = SYSCLK_FREQ_120MHz_HSI; /* System Clock Frequency (Core Clock) */
|
||||
#elif defined SYSCLK_FREQ_144MHz_HSI
|
||||
uint32_t SystemCoreClock = SYSCLK_FREQ_144MHz_HSI; /* System Clock Frequency (Core Clock) */
|
||||
#else
|
||||
uint32_t SystemCoreClock = HSI_VALUE; /* System Clock Frequency (Core Clock) */
|
||||
|
||||
#endif
|
||||
|
||||
__I uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9};
|
||||
|
||||
|
||||
/* system_private_function_proto_types */
|
||||
static void SetSysClock(void);
|
||||
|
||||
#ifdef SYSCLK_FREQ_HSE
|
||||
static void SetSysClockToHSE( void );
|
||||
#elif defined SYSCLK_FREQ_48MHz_HSE
|
||||
static void SetSysClockTo48_HSE( void );
|
||||
#elif defined SYSCLK_FREQ_56MHz_HSE
|
||||
static void SetSysClockTo56_HSE( void );
|
||||
#elif defined SYSCLK_FREQ_72MHz_HSE
|
||||
static void SetSysClockTo72_HSE( void );
|
||||
#elif defined SYSCLK_FREQ_96MHz_HSE
|
||||
static void SetSysClockTo96_HSE( void );
|
||||
#elif defined SYSCLK_FREQ_120MHz_HSE
|
||||
static void SetSysClockTo120_HSE( void );
|
||||
#elif defined SYSCLK_FREQ_144MHz_HSE
|
||||
static void SetSysClockTo144_HSE( void );
|
||||
#elif defined SYSCLK_FREQ_48MHz_HSI
|
||||
static void SetSysClockTo48_HSI( void );
|
||||
#elif defined SYSCLK_FREQ_56MHz_HSI
|
||||
static void SetSysClockTo56_HSI( void );
|
||||
#elif defined SYSCLK_FREQ_72MHz_HSI
|
||||
static void SetSysClockTo72_HSI( void );
|
||||
#elif defined SYSCLK_FREQ_96MHz_HSI
|
||||
static void SetSysClockTo96_HSI( void );
|
||||
#elif defined SYSCLK_FREQ_120MHz_HSI
|
||||
static void SetSysClockTo120_HSI( void );
|
||||
#elif defined SYSCLK_FREQ_144MHz_HSI
|
||||
static void SetSysClockTo144_HSI( void );
|
||||
|
||||
#endif
|
||||
|
||||
/*********************************************************************
|
||||
* @fn SystemInit
|
||||
*
|
||||
* @brief Setup the microcontroller system Initialize the Embedded Flash Interface,
|
||||
* the PLL and update the SystemCoreClock variable.
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
void SystemInit (void)
|
||||
{
|
||||
RCC->CTLR |= (uint32_t)0x00000001;
|
||||
RCC->CFGR0 &= (uint32_t)0xF8FF0000;
|
||||
RCC->CTLR &= (uint32_t)0xFEF6FFFF;
|
||||
RCC->CTLR &= (uint32_t)0xFFFBFFFF;
|
||||
RCC->CFGR0 &= (uint32_t)0xFF80FFFF;
|
||||
RCC->INTR = 0x009F0000;
|
||||
SetSysClock();
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
* @fn SystemCoreClockUpdate
|
||||
*
|
||||
* @brief Update SystemCoreClock variable according to Clock Register Values.
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
void SystemCoreClockUpdate (void)
|
||||
{
|
||||
uint32_t tmp = 0, pllmull = 0, pllsource = 0, Pll_6_5 = 0;
|
||||
|
||||
tmp = RCC->CFGR0 & RCC_SWS;
|
||||
|
||||
switch (tmp)
|
||||
{
|
||||
case 0x00:
|
||||
SystemCoreClock = HSI_VALUE;
|
||||
break;
|
||||
case 0x04:
|
||||
SystemCoreClock = HSE_VALUE;
|
||||
break;
|
||||
case 0x08:
|
||||
pllmull = RCC->CFGR0 & RCC_PLLMULL;
|
||||
pllsource = RCC->CFGR0 & RCC_PLLSRC;
|
||||
pllmull = ( pllmull >> 18) + 2;
|
||||
|
||||
if(pllmull == 17) pllmull = 18;
|
||||
|
||||
if (pllsource == 0x00)
|
||||
{
|
||||
if(EXTEN->EXTEN_CTR & EXTEN_PLL_HSI_PRE){
|
||||
SystemCoreClock = HSI_VALUE * pllmull;
|
||||
}
|
||||
else{
|
||||
SystemCoreClock = (HSI_VALUE >> 1) * pllmull;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
#if defined (CH32V20x_D8W)
|
||||
if((RCC->CFGR0 & (3<<22)) == (3<<22))
|
||||
{
|
||||
SystemCoreClock = ((HSE_VALUE>>1)) * pllmull;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if ((RCC->CFGR0 & RCC_PLLXTPRE) != (uint32_t)RESET)
|
||||
{
|
||||
#if defined (CH32V20x_D8) || defined (CH32V20x_D8W)
|
||||
SystemCoreClock = ((HSE_VALUE>>2) >> 1) * pllmull;
|
||||
#else
|
||||
SystemCoreClock = (HSE_VALUE >> 1) * pllmull;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#if defined (CH32V20x_D8) || defined (CH32V20x_D8W)
|
||||
SystemCoreClock = (HSE_VALUE>>2) * pllmull;
|
||||
#else
|
||||
SystemCoreClock = HSE_VALUE * pllmull;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if(Pll_6_5 == 1) SystemCoreClock = (SystemCoreClock / 2);
|
||||
|
||||
break;
|
||||
default:
|
||||
SystemCoreClock = HSI_VALUE;
|
||||
break;
|
||||
}
|
||||
|
||||
tmp = AHBPrescTable[((RCC->CFGR0 & RCC_HPRE) >> 4)];
|
||||
SystemCoreClock >>= tmp;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* @fn SetSysClock
|
||||
*
|
||||
* @brief Configures the System clock frequency, HCLK, PCLK2 and PCLK1 prescalers.
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
static void SetSysClock(void)
|
||||
{
|
||||
#ifdef SYSCLK_FREQ_HSE
|
||||
SetSysClockToHSE();
|
||||
#elif defined SYSCLK_FREQ_48MHz_HSE
|
||||
SetSysClockTo48_HSE();
|
||||
#elif defined SYSCLK_FREQ_56MHz_HSE
|
||||
SetSysClockTo56_HSE();
|
||||
#elif defined SYSCLK_FREQ_72MHz_HSE
|
||||
SetSysClockTo72_HSE();
|
||||
#elif defined SYSCLK_FREQ_96MHz_HSE
|
||||
SetSysClockTo96_HSE();
|
||||
#elif defined SYSCLK_FREQ_120MHz_HSE
|
||||
SetSysClockTo120_HSE();
|
||||
#elif defined SYSCLK_FREQ_144MHz_HSE
|
||||
SetSysClockTo144_HSE();
|
||||
#elif defined SYSCLK_FREQ_48MHz_HSI
|
||||
SetSysClockTo48_HSI();
|
||||
#elif defined SYSCLK_FREQ_56MHz_HSI
|
||||
SetSysClockTo56_HSI();
|
||||
#elif defined SYSCLK_FREQ_72MHz_HSI
|
||||
SetSysClockTo72_HSI();
|
||||
#elif defined SYSCLK_FREQ_96MHz_HSI
|
||||
SetSysClockTo96_HSI();
|
||||
#elif defined SYSCLK_FREQ_120MHz_HSI
|
||||
SetSysClockTo120_HSI();
|
||||
#elif defined SYSCLK_FREQ_144MHz_HSI
|
||||
SetSysClockTo144_HSI();
|
||||
|
||||
#endif
|
||||
|
||||
/* If none of the define above is enabled, the HSI is used as System clock
|
||||
* source (default after reset)
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
#ifdef SYSCLK_FREQ_HSE
|
||||
|
||||
/*********************************************************************
|
||||
* @fn SetSysClockToHSE
|
||||
*
|
||||
* @brief Sets HSE as System clock source and configure HCLK, PCLK2 and PCLK1 prescalers.
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
static void SetSysClockToHSE(void)
|
||||
{
|
||||
__IO uint32_t StartUpCounter = 0, HSEStatus = 0;
|
||||
|
||||
|
||||
RCC->CTLR |= ((uint32_t)RCC_HSEON);
|
||||
|
||||
/* Wait till HSE is ready and if Time out is reached exit */
|
||||
do
|
||||
{
|
||||
HSEStatus = RCC->CTLR & RCC_HSERDY;
|
||||
StartUpCounter++;
|
||||
} while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
|
||||
|
||||
if ((RCC->CTLR & RCC_HSERDY) != RESET)
|
||||
{
|
||||
HSEStatus = (uint32_t)0x01;
|
||||
}
|
||||
else
|
||||
{
|
||||
HSEStatus = (uint32_t)0x00;
|
||||
}
|
||||
|
||||
if (HSEStatus == (uint32_t)0x01)
|
||||
{
|
||||
/* HCLK = SYSCLK */
|
||||
RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1;
|
||||
/* PCLK2 = HCLK */
|
||||
RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1;
|
||||
/* PCLK1 = HCLK */
|
||||
RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV1;
|
||||
|
||||
/* Select HSE as system clock source
|
||||
* CH32V20x_D6 (HSE=8MHZ)
|
||||
* CH32V20x_D8 (HSE=32MHZ)
|
||||
* CH32V20x_D8W (HSE=32MHZ)
|
||||
*/
|
||||
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_SW));
|
||||
RCC->CFGR0 |= (uint32_t)RCC_SW_HSE;
|
||||
|
||||
/* Wait till HSE is used as system clock source */
|
||||
while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x04)
|
||||
{
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If HSE fails to start-up, the application will have wrong clock
|
||||
* configuration. User can add here some code to deal with this error
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
#elif defined SYSCLK_FREQ_48MHz_HSE
|
||||
|
||||
/*********************************************************************
|
||||
* @fn SetSysClockTo48_HSE
|
||||
*
|
||||
* @brief Sets System clock frequency to 48MHz and configure HCLK, PCLK2 and PCLK1 prescalers.
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
static void SetSysClockTo48_HSE(void)
|
||||
{
|
||||
__IO uint32_t StartUpCounter = 0, HSEStatus = 0;
|
||||
|
||||
|
||||
RCC->CTLR |= ((uint32_t)RCC_HSEON);
|
||||
/* Wait till HSE is ready and if Time out is reached exit */
|
||||
do
|
||||
{
|
||||
HSEStatus = RCC->CTLR & RCC_HSERDY;
|
||||
StartUpCounter++;
|
||||
} while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
|
||||
|
||||
if ((RCC->CTLR & RCC_HSERDY) != RESET)
|
||||
{
|
||||
HSEStatus = (uint32_t)0x01;
|
||||
}
|
||||
else
|
||||
{
|
||||
HSEStatus = (uint32_t)0x00;
|
||||
}
|
||||
|
||||
if (HSEStatus == (uint32_t)0x01)
|
||||
{
|
||||
/* HCLK = SYSCLK */
|
||||
RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1;
|
||||
/* PCLK2 = HCLK */
|
||||
RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1;
|
||||
/* PCLK1 = HCLK */
|
||||
RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV2;
|
||||
|
||||
/* CH32V20x_D6-PLL configuration: PLLCLK = HSE * 6 = 48 MHz (HSE=8MHZ)
|
||||
* CH32V20x_D8-PLL configuration: PLLCLK = HSE/4 * 6 = 48 MHz (HSE=32MHZ)
|
||||
* CH32V20x_D8W-PLL configuration: PLLCLK = HSE/4 * 6 = 48 MHz (HSE=32MHZ)
|
||||
*/
|
||||
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC | RCC_PLLXTPRE | RCC_PLLMULL));
|
||||
|
||||
RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL6);
|
||||
|
||||
/* Enable PLL */
|
||||
RCC->CTLR |= RCC_PLLON;
|
||||
/* Wait till PLL is ready */
|
||||
while((RCC->CTLR & RCC_PLLRDY) == 0)
|
||||
{
|
||||
}
|
||||
/* Select PLL as system clock source */
|
||||
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_SW));
|
||||
RCC->CFGR0 |= (uint32_t)RCC_SW_PLL;
|
||||
/* Wait till PLL is used as system clock source */
|
||||
while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08)
|
||||
{
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* If HSE fails to start-up, the application will have wrong clock
|
||||
* configuration. User can add here some code to deal with this error
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
#elif defined SYSCLK_FREQ_56MHz_HSE
|
||||
|
||||
/*********************************************************************
|
||||
* @fn SetSysClockTo56_HSE
|
||||
*
|
||||
* @brief Sets System clock frequency to 56MHz and configure HCLK, PCLK2 and PCLK1 prescalers.
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
static void SetSysClockTo56_HSE(void)
|
||||
{
|
||||
__IO uint32_t StartUpCounter = 0, HSEStatus = 0;
|
||||
|
||||
RCC->CTLR |= ((uint32_t)RCC_HSEON);
|
||||
|
||||
/* Wait till HSE is ready and if Time out is reached exit */
|
||||
do
|
||||
{
|
||||
HSEStatus = RCC->CTLR & RCC_HSERDY;
|
||||
StartUpCounter++;
|
||||
} while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
|
||||
|
||||
if ((RCC->CTLR & RCC_HSERDY) != RESET)
|
||||
{
|
||||
HSEStatus = (uint32_t)0x01;
|
||||
}
|
||||
else
|
||||
{
|
||||
HSEStatus = (uint32_t)0x00;
|
||||
}
|
||||
|
||||
if (HSEStatus == (uint32_t)0x01)
|
||||
{
|
||||
/* HCLK = SYSCLK */
|
||||
RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1;
|
||||
/* PCLK2 = HCLK */
|
||||
RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1;
|
||||
/* PCLK1 = HCLK */
|
||||
RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV2;
|
||||
|
||||
/* CH32V20x_D6-PLL configuration: PLLCLK = HSE * 7 = 56 MHz (HSE=8MHZ)
|
||||
* CH32V20x_D8-PLL configuration: PLLCLK = HSE/4 * 7 = 56 MHz (HSE=32MHZ)
|
||||
* CH32V20x_D8W-PLL configuration: PLLCLK = HSE/4 * 7 = 56 MHz (HSE=32MHZ)
|
||||
*/
|
||||
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC | RCC_PLLXTPRE | RCC_PLLMULL));
|
||||
|
||||
RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL7);
|
||||
|
||||
/* Enable PLL */
|
||||
RCC->CTLR |= RCC_PLLON;
|
||||
/* Wait till PLL is ready */
|
||||
while((RCC->CTLR & RCC_PLLRDY) == 0)
|
||||
{
|
||||
}
|
||||
|
||||
/* Select PLL as system clock source */
|
||||
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_SW));
|
||||
RCC->CFGR0 |= (uint32_t)RCC_SW_PLL;
|
||||
/* Wait till PLL is used as system clock source */
|
||||
while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08)
|
||||
{
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* If HSE fails to start-up, the application will have wrong clock
|
||||
* configuration. User can add here some code to deal with this error
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
#elif defined SYSCLK_FREQ_72MHz_HSE
|
||||
|
||||
/*********************************************************************
|
||||
* @fn SetSysClockTo72_HSE
|
||||
*
|
||||
* @brief Sets System clock frequency to 72MHz and configure HCLK, PCLK2 and PCLK1 prescalers.
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
static void SetSysClockTo72_HSE(void)
|
||||
{
|
||||
__IO uint32_t StartUpCounter = 0, HSEStatus = 0;
|
||||
|
||||
RCC->CTLR |= ((uint32_t)RCC_HSEON);
|
||||
|
||||
/* Wait till HSE is ready and if Time out is reached exit */
|
||||
do
|
||||
{
|
||||
HSEStatus = RCC->CTLR & RCC_HSERDY;
|
||||
StartUpCounter++;
|
||||
} while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
|
||||
|
||||
if ((RCC->CTLR & RCC_HSERDY) != RESET)
|
||||
{
|
||||
HSEStatus = (uint32_t)0x01;
|
||||
}
|
||||
else
|
||||
{
|
||||
HSEStatus = (uint32_t)0x00;
|
||||
}
|
||||
|
||||
if (HSEStatus == (uint32_t)0x01)
|
||||
{
|
||||
/* HCLK = SYSCLK */
|
||||
RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1;
|
||||
/* PCLK2 = HCLK */
|
||||
RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1;
|
||||
/* PCLK1 = HCLK */
|
||||
RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV2;
|
||||
|
||||
|
||||
/* CH32V20x_D6-PLL configuration: PLLCLK = HSE * 9 = 72 MHz (HSE=8MHZ)
|
||||
* CH32V20x_D8-PLL configuration: PLLCLK = HSE/4 * 9 = 72 MHz (HSE=32MHZ)
|
||||
* CH32V20x_D8W-PLL configuration: PLLCLK = HSE/4 * 9 = 72 MHz (HSE=32MHZ)
|
||||
*/
|
||||
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC | RCC_PLLXTPRE |
|
||||
RCC_PLLMULL));
|
||||
|
||||
RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL9);
|
||||
|
||||
/* Enable PLL */
|
||||
RCC->CTLR |= RCC_PLLON;
|
||||
/* Wait till PLL is ready */
|
||||
while((RCC->CTLR & RCC_PLLRDY) == 0)
|
||||
{
|
||||
}
|
||||
/* Select PLL as system clock source */
|
||||
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_SW));
|
||||
RCC->CFGR0 |= (uint32_t)RCC_SW_PLL;
|
||||
/* Wait till PLL is used as system clock source */
|
||||
while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08)
|
||||
{
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* If HSE fails to start-up, the application will have wrong clock
|
||||
* configuration. User can add here some code to deal with this error
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#elif defined SYSCLK_FREQ_96MHz_HSE
|
||||
|
||||
/*********************************************************************
|
||||
* @fn SetSysClockTo96_HSE
|
||||
*
|
||||
* @brief Sets System clock frequency to 96MHz and configure HCLK, PCLK2 and PCLK1 prescalers.
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
static void SetSysClockTo96_HSE(void)
|
||||
{
|
||||
__IO uint32_t StartUpCounter = 0, HSEStatus = 0;
|
||||
|
||||
RCC->CTLR |= ((uint32_t)RCC_HSEON);
|
||||
|
||||
/* Wait till HSE is ready and if Time out is reached exit */
|
||||
do
|
||||
{
|
||||
HSEStatus = RCC->CTLR & RCC_HSERDY;
|
||||
StartUpCounter++;
|
||||
} while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
|
||||
|
||||
if ((RCC->CTLR & RCC_HSERDY) != RESET)
|
||||
{
|
||||
HSEStatus = (uint32_t)0x01;
|
||||
}
|
||||
else
|
||||
{
|
||||
HSEStatus = (uint32_t)0x00;
|
||||
}
|
||||
|
||||
if (HSEStatus == (uint32_t)0x01)
|
||||
{
|
||||
/* HCLK = SYSCLK */
|
||||
RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1;
|
||||
/* PCLK2 = HCLK */
|
||||
RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1;
|
||||
/* PCLK1 = HCLK */
|
||||
RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV2;
|
||||
|
||||
|
||||
/* CH32V20x_D6-PLL configuration: PLLCLK = HSE * 12 = 96 MHz (HSE=8MHZ)
|
||||
* CH32V20x_D8-PLL configuration: PLLCLK = HSE/4 * 12 = 96 MHz (HSE=32MHZ)
|
||||
* CH32V20x_D8W-PLL configuration: PLLCLK = HSE/4 * 12 = 96 MHz (HSE=32MHZ)
|
||||
*/
|
||||
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC | RCC_PLLXTPRE |
|
||||
RCC_PLLMULL));
|
||||
|
||||
RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL12);
|
||||
|
||||
/* Enable PLL */
|
||||
RCC->CTLR |= RCC_PLLON;
|
||||
/* Wait till PLL is ready */
|
||||
while((RCC->CTLR & RCC_PLLRDY) == 0)
|
||||
{
|
||||
}
|
||||
/* Select PLL as system clock source */
|
||||
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_SW));
|
||||
RCC->CFGR0 |= (uint32_t)RCC_SW_PLL;
|
||||
/* Wait till PLL is used as system clock source */
|
||||
while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08)
|
||||
{
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* If HSE fails to start-up, the application will have wrong clock
|
||||
* configuration. User can add here some code to deal with this error
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#elif defined SYSCLK_FREQ_120MHz_HSE
|
||||
|
||||
/*********************************************************************
|
||||
* @fn SetSysClockTo120_HSE
|
||||
*
|
||||
* @brief Sets System clock frequency to 120MHz and configure HCLK, PCLK2 and PCLK1 prescalers.
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
static void SetSysClockTo120_HSE(void)
|
||||
{
|
||||
__IO uint32_t StartUpCounter = 0, HSEStatus = 0;
|
||||
|
||||
RCC->CTLR |= ((uint32_t)RCC_HSEON);
|
||||
|
||||
/* Wait till HSE is ready and if Time out is reached exit */
|
||||
do
|
||||
{
|
||||
HSEStatus = RCC->CTLR & RCC_HSERDY;
|
||||
StartUpCounter++;
|
||||
} while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
|
||||
|
||||
if((RCC->CTLR & RCC_HSERDY) != RESET)
|
||||
{
|
||||
HSEStatus = (uint32_t)0x01;
|
||||
}
|
||||
else
|
||||
{
|
||||
HSEStatus = (uint32_t)0x00;
|
||||
}
|
||||
|
||||
if(HSEStatus == (uint32_t)0x01)
|
||||
{
|
||||
#if defined (CH32V20x_D8W)
|
||||
RCC->CFGR0 |= (uint32_t)(3<<22);
|
||||
/* HCLK = SYSCLK/2 */
|
||||
RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV2;
|
||||
#else
|
||||
/* HCLK = SYSCLK */
|
||||
RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1;
|
||||
#endif
|
||||
/* PCLK2 = HCLK */
|
||||
RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1;
|
||||
/* PCLK1 = HCLK */
|
||||
RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV2;
|
||||
|
||||
/* CH32V20x_D6-PLL configuration: PLLCLK = HSE * 15 = 120 MHz (HSE=8MHZ)
|
||||
* CH32V20x_D8-PLL configuration: PLLCLK = HSE/4 * 15 = 120 MHz (HSE=32MHZ)
|
||||
* CH32V20x_D8W-PLL configuration: PLLCLK = HSE/2 * 15 = 240 MHz (HSE=32MHZ)
|
||||
*/
|
||||
RCC->CFGR0 &= (uint32_t)((uint32_t) ~(RCC_PLLSRC | RCC_PLLXTPRE |
|
||||
RCC_PLLMULL));
|
||||
|
||||
RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL15);
|
||||
|
||||
/* Enable PLL */
|
||||
RCC->CTLR |= RCC_PLLON;
|
||||
/* Wait till PLL is ready */
|
||||
while((RCC->CTLR & RCC_PLLRDY) == 0)
|
||||
{
|
||||
}
|
||||
/* Select PLL as system clock source */
|
||||
RCC->CFGR0 &= (uint32_t)((uint32_t) ~(RCC_SW));
|
||||
RCC->CFGR0 |= (uint32_t)RCC_SW_PLL;
|
||||
/* Wait till PLL is used as system clock source */
|
||||
while((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08)
|
||||
{
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* If HSE fails to start-up, the application will have wrong clock
|
||||
* configuration. User can add here some code to deal with this error
|
||||
*/
|
||||
}
|
||||
}
|
||||
#elif defined SYSCLK_FREQ_144MHz_HSE
|
||||
|
||||
/*********************************************************************
|
||||
* @fn SetSysClockTo144_HSE
|
||||
*
|
||||
* @brief Sets System clock frequency to 144MHz and configure HCLK, PCLK2 and PCLK1 prescalers.
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
static void SetSysClockTo144_HSE(void)
|
||||
{
|
||||
__IO uint32_t StartUpCounter = 0, HSEStatus = 0;
|
||||
|
||||
RCC->CTLR |= ((uint32_t)RCC_HSEON);
|
||||
|
||||
/* Wait till HSE is ready and if Time out is reached exit */
|
||||
do
|
||||
{
|
||||
HSEStatus = RCC->CTLR & RCC_HSERDY;
|
||||
StartUpCounter++;
|
||||
} while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
|
||||
|
||||
if ((RCC->CTLR & RCC_HSERDY) != RESET)
|
||||
{
|
||||
HSEStatus = (uint32_t)0x01;
|
||||
}
|
||||
else
|
||||
{
|
||||
HSEStatus = (uint32_t)0x00;
|
||||
}
|
||||
|
||||
if (HSEStatus == (uint32_t)0x01)
|
||||
{
|
||||
/* HCLK = SYSCLK */
|
||||
RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1;
|
||||
/* PCLK2 = HCLK */
|
||||
RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1;
|
||||
/* PCLK1 = HCLK */
|
||||
RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV2;
|
||||
|
||||
|
||||
/* CH32V20x_D6-PLL configuration: PLLCLK = HSE * 18 = 144 MHz (HSE=8MHZ)
|
||||
* CH32V20x_D8-PLL configuration: PLLCLK = HSE/4 * 18 = 144 MHz (HSE=32MHZ)
|
||||
* CH32V20x_D8W-PLL configuration: PLLCLK = HSE/4 * 18 = 144 MHz (HSE=32MHZ)
|
||||
*/
|
||||
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC | RCC_PLLXTPRE |
|
||||
RCC_PLLMULL));
|
||||
|
||||
RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL18);
|
||||
|
||||
/* Enable PLL */
|
||||
RCC->CTLR |= RCC_PLLON;
|
||||
/* Wait till PLL is ready */
|
||||
while((RCC->CTLR & RCC_PLLRDY) == 0)
|
||||
{
|
||||
}
|
||||
/* Select PLL as system clock source */
|
||||
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_SW));
|
||||
RCC->CFGR0 |= (uint32_t)RCC_SW_PLL;
|
||||
/* Wait till PLL is used as system clock source */
|
||||
while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08)
|
||||
{
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* If HSE fails to start-up, the application will have wrong clock
|
||||
* configuration. User can add here some code to deal with this error
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
#elif defined SYSCLK_FREQ_48MHz_HSI
|
||||
|
||||
/*********************************************************************
|
||||
* @fn SetSysClockTo48_HSI
|
||||
*
|
||||
* @brief Sets System clock frequency to 48MHz and configure HCLK, PCLK2 and PCLK1 prescalers.
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
static void SetSysClockTo48_HSI(void)
|
||||
{
|
||||
EXTEN->EXTEN_CTR |= EXTEN_PLL_HSI_PRE;
|
||||
|
||||
/* HCLK = SYSCLK */
|
||||
RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1;
|
||||
/* PCLK2 = HCLK */
|
||||
RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1;
|
||||
/* PCLK1 = HCLK */
|
||||
RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV2;
|
||||
|
||||
/* PLL configuration: PLLCLK = HSI * 6 = 48 MHz */
|
||||
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC | RCC_PLLXTPRE | RCC_PLLMULL));
|
||||
|
||||
RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSI_Div2 | RCC_PLLMULL6);
|
||||
|
||||
/* Enable PLL */
|
||||
RCC->CTLR |= RCC_PLLON;
|
||||
/* Wait till PLL is ready */
|
||||
while((RCC->CTLR & RCC_PLLRDY) == 0)
|
||||
{
|
||||
}
|
||||
/* Select PLL as system clock source */
|
||||
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_SW));
|
||||
RCC->CFGR0 |= (uint32_t)RCC_SW_PLL;
|
||||
/* Wait till PLL is used as system clock source */
|
||||
while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
#elif defined SYSCLK_FREQ_56MHz_HSI
|
||||
|
||||
/*********************************************************************
|
||||
* @fn SetSysClockTo56_HSI
|
||||
*
|
||||
* @brief Sets System clock frequency to 56MHz and configure HCLK, PCLK2 and PCLK1 prescalers.
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
static void SetSysClockTo56_HSI(void)
|
||||
{
|
||||
EXTEN->EXTEN_CTR |= EXTEN_PLL_HSI_PRE;
|
||||
|
||||
/* HCLK = SYSCLK */
|
||||
RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1;
|
||||
/* PCLK2 = HCLK */
|
||||
RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1;
|
||||
/* PCLK1 = HCLK */
|
||||
RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV2;
|
||||
|
||||
/* PLL configuration: PLLCLK = HSI * 7 = 48 MHz */
|
||||
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC | RCC_PLLXTPRE | RCC_PLLMULL));
|
||||
|
||||
RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSI_Div2 | RCC_PLLMULL7);
|
||||
|
||||
/* Enable PLL */
|
||||
RCC->CTLR |= RCC_PLLON;
|
||||
/* Wait till PLL is ready */
|
||||
while((RCC->CTLR & RCC_PLLRDY) == 0)
|
||||
{
|
||||
}
|
||||
/* Select PLL as system clock source */
|
||||
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_SW));
|
||||
RCC->CFGR0 |= (uint32_t)RCC_SW_PLL;
|
||||
/* Wait till PLL is used as system clock source */
|
||||
while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
#elif defined SYSCLK_FREQ_72MHz_HSI
|
||||
|
||||
/*********************************************************************
|
||||
* @fn SetSysClockTo72_HSI
|
||||
*
|
||||
* @brief Sets System clock frequency to 72MHz and configure HCLK, PCLK2 and PCLK1 prescalers.
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
static void SetSysClockTo72_HSI(void)
|
||||
{
|
||||
EXTEN->EXTEN_CTR |= EXTEN_PLL_HSI_PRE;
|
||||
|
||||
/* HCLK = SYSCLK */
|
||||
RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1;
|
||||
/* PCLK2 = HCLK */
|
||||
RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1;
|
||||
/* PCLK1 = HCLK */
|
||||
RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV2;
|
||||
|
||||
/* PLL configuration: PLLCLK = HSI * 9 = 72 MHz */
|
||||
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC | RCC_PLLXTPRE | RCC_PLLMULL));
|
||||
|
||||
RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSI_Div2 | RCC_PLLMULL9);
|
||||
|
||||
/* Enable PLL */
|
||||
RCC->CTLR |= RCC_PLLON;
|
||||
/* Wait till PLL is ready */
|
||||
while((RCC->CTLR & RCC_PLLRDY) == 0)
|
||||
{
|
||||
}
|
||||
/* Select PLL as system clock source */
|
||||
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_SW));
|
||||
RCC->CFGR0 |= (uint32_t)RCC_SW_PLL;
|
||||
/* Wait till PLL is used as system clock source */
|
||||
while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#elif defined SYSCLK_FREQ_96MHz_HSI
|
||||
|
||||
/*********************************************************************
|
||||
* @fn SetSysClockTo96_HSI
|
||||
*
|
||||
* @brief Sets System clock frequency to 96MHz and configure HCLK, PCLK2 and PCLK1 prescalers.
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
static void SetSysClockTo96_HSI(void)
|
||||
{
|
||||
EXTEN->EXTEN_CTR |= EXTEN_PLL_HSI_PRE;
|
||||
|
||||
/* HCLK = SYSCLK */
|
||||
RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1;
|
||||
/* PCLK2 = HCLK */
|
||||
RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1;
|
||||
/* PCLK1 = HCLK */
|
||||
RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV2;
|
||||
|
||||
/* PLL configuration: PLLCLK = HSI * 12 = 96 MHz */
|
||||
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC | RCC_PLLXTPRE | RCC_PLLMULL));
|
||||
|
||||
RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSI_Div2 | RCC_PLLMULL12);
|
||||
|
||||
/* Enable PLL */
|
||||
RCC->CTLR |= RCC_PLLON;
|
||||
/* Wait till PLL is ready */
|
||||
while((RCC->CTLR & RCC_PLLRDY) == 0)
|
||||
{
|
||||
}
|
||||
/* Select PLL as system clock source */
|
||||
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_SW));
|
||||
RCC->CFGR0 |= (uint32_t)RCC_SW_PLL;
|
||||
/* Wait till PLL is used as system clock source */
|
||||
while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#elif defined SYSCLK_FREQ_120MHz_HSI
|
||||
|
||||
/*********************************************************************
|
||||
* @fn SetSysClockTo120_HSI
|
||||
*
|
||||
* @brief Sets System clock frequency to 120MHz and configure HCLK, PCLK2 and PCLK1 prescalers.
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
static void SetSysClockTo120_HSI(void)
|
||||
{
|
||||
EXTEN->EXTEN_CTR |= EXTEN_PLL_HSI_PRE;
|
||||
|
||||
/* HCLK = SYSCLK */
|
||||
RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1;
|
||||
/* PCLK2 = HCLK */
|
||||
RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1;
|
||||
/* PCLK1 = HCLK */
|
||||
RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV2;
|
||||
|
||||
/* PLL configuration: PLLCLK = HSI * 15 = 120 MHz */
|
||||
RCC->CFGR0 &= (uint32_t)((uint32_t) ~(RCC_PLLSRC | RCC_PLLXTPRE |
|
||||
RCC_PLLMULL));
|
||||
|
||||
RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSI_Div2 | RCC_PLLMULL15);
|
||||
|
||||
/* Enable PLL */
|
||||
RCC->CTLR |= RCC_PLLON;
|
||||
/* Wait till PLL is ready */
|
||||
while((RCC->CTLR & RCC_PLLRDY) == 0)
|
||||
{
|
||||
}
|
||||
/* Select PLL as system clock source */
|
||||
RCC->CFGR0 &= (uint32_t)((uint32_t) ~(RCC_SW));
|
||||
RCC->CFGR0 |= (uint32_t)RCC_SW_PLL;
|
||||
/* Wait till PLL is used as system clock source */
|
||||
while((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08)
|
||||
{
|
||||
}
|
||||
}
|
||||
#elif defined SYSCLK_FREQ_144MHz_HSI
|
||||
|
||||
/*********************************************************************
|
||||
* @fn SetSysClockTo144_HSI
|
||||
*
|
||||
* @brief Sets System clock frequency to 144MHz and configure HCLK, PCLK2 and PCLK1 prescalers.
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
static void SetSysClockTo144_HSI(void)
|
||||
{
|
||||
EXTEN->EXTEN_CTR |= EXTEN_PLL_HSI_PRE;
|
||||
|
||||
/* HCLK = SYSCLK */
|
||||
RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1;
|
||||
/* PCLK2 = HCLK */
|
||||
RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1;
|
||||
/* PCLK1 = HCLK */
|
||||
RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV2;
|
||||
|
||||
/* PLL configuration: PLLCLK = HSI * 18 = 144 MHz */
|
||||
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC | RCC_PLLXTPRE | RCC_PLLMULL));
|
||||
|
||||
RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSI_Div2 | RCC_PLLMULL18);
|
||||
|
||||
/* Enable PLL */
|
||||
RCC->CTLR |= RCC_PLLON;
|
||||
/* Wait till PLL is ready */
|
||||
while((RCC->CTLR & RCC_PLLRDY) == 0)
|
||||
{
|
||||
}
|
||||
/* Select PLL as system clock source */
|
||||
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_SW));
|
||||
RCC->CFGR0 |= (uint32_t)RCC_SW_PLL;
|
||||
/* Wait till PLL is used as system clock source */
|
||||
while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user