Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions boards/st/nucleo_wb05kz/nucleo_wb05kz.dts
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,10 @@
status = "okay";
};

&radio_timer {
status = "okay";
};

&usart1 {
pinctrl-0 = <&usart1_tx_pa1 &usart1_rx_pb0>;
pinctrl-names = "default";
Expand Down
4 changes: 4 additions & 0 deletions boards/st/nucleo_wb07cc/nucleo_wb07cc.dts
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,10 @@
status = "okay";
};

&radio_timer {
status = "okay";
};

&usart1 {
pinctrl-0 = <&usart1_tx_pa9 &usart1_rx_pa8>;
pinctrl-names = "default";
Expand Down
36 changes: 36 additions & 0 deletions boards/st/nucleo_wb09ke/nucleo_wb09ke.dts
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@
&pwrc {
smps-mode = "RUN";
smps-bom = <3>;
smps-lp-floating;
};

&clk_lse {
Expand Down Expand Up @@ -129,10 +130,45 @@
status = "okay";
};

/* Optimize power consumption during lower power state */
&gpioa {
gpios-pull-up {
gpio-hog;
gpios = <0 GPIO_PULL_UP>;
input;
};

gpios-pull-down {
gpio-hog;
gpios = <8 GPIO_PULL_DOWN>, <9 GPIO_PULL_DOWN>,
<10 GPIO_PULL_DOWN>, <11 GPIO_PULL_DOWN>;
input;
};
};

&gpiob {
gpios-pull-up {
gpio-hog;
gpios = <1 GPIO_PULL_UP>, <2 GPIO_PULL_UP>, <4 GPIO_PULL_UP>,
<5 GPIO_PULL_UP>, <14 GPIO_PULL_UP>, <15 GPIO_PULL_UP>;
input;
};

gpios-pull-down {
gpio-hog;
gpios = <3 GPIO_PULL_DOWN>, <6 GPIO_PULL_DOWN>, <7 GPIO_PULL_DOWN>;
input;
};
};

&bt_hci_wb0 {
status = "okay";
};

&radio_timer {
status = "okay";
};

&usart1 {
pinctrl-0 = <&usart1_tx_pa1 &usart1_rx_pb0>;
pinctrl-names = "default";
Expand Down
2 changes: 1 addition & 1 deletion drivers/adc/adc_stm32wb0.c
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ LOG_MODULE_REGISTER(adc_stm32wb0, CONFIG_ADC_LOG_LEVEL);
#define ADC_CHANNEL_TYPE_INVALID (0xFFU) /* Invalid */

/** See RM0505 §6.2.1 "System clock details" */
BUILD_ASSERT(CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC >= (8 * 1000 * 1000),
BUILD_ASSERT(STM32_HCLK_FREQUENCY >= (8 * 1000 * 1000),
"STM32WB0: system clock frequency must be at least 8MHz to use ADC");

/**
Expand Down
183 changes: 111 additions & 72 deletions drivers/bluetooth/hci/hci_stm32wb0.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
#include <zephyr/bluetooth/hci_types.h>
#include <zephyr/drivers/bluetooth.h>
#include <zephyr/drivers/entropy.h>
#include <zephyr/pm/policy.h>
#include <zephyr/pm/device.h>
#include "bleplat_cntr.h"
#include "ble_stack.h"
#include "stm32wb0x_hal_radio_timer.h"
Expand All @@ -30,16 +32,8 @@ LOG_MODULE_REGISTER(bt_driver);

#define DT_DRV_COMPAT st_hci_stm32wb0

/* Max HS startup time expressed in system time (1953 us / 2.4414 us) */
#define MAX_HS_STARTUP_TIME 320
#define BLE_WKUP_PRIO 0
#define BLE_WKUP_FLAGS 0
#define BLE_TX_RX_PRIO 0
#define BLE_TX_RX_FLAGS 0
#define CPU_WKUP_PRIO 1
#define CPU_WKUP_FLAGS 0
#define BLE_ERROR_PRIO 3
#define BLE_ERROR_FLAGS 0
#define BLE_RXTX_SEQ_PRIO 3
#define BLE_RXTX_SEQ_FLAGS 0
#define PKA_PRIO 2
Expand All @@ -56,14 +50,35 @@ LOG_MODULE_REGISTER(bt_driver);
#define EVT_VENDOR_CODE_LSB 3
#define EVT_VENDOR_CODE_MSB 4

#if (defined(CONFIG_SOC_STM32WB06XX) || defined(CONFIG_SOC_STM32WB07XX)) && defined(CONFIG_PM)
#error "PM is not supported yet for WB06/WB07"
#endif /* (CONFIG_SOC_STM32WB06XX || CONFIG_SOC_STM32WB07XX) && CONFIG_PM */

static uint32_t __noinit dyn_alloc_a[BLE_DYN_ALLOC_SIZE >> 2];
static uint8_t buffer_out_mem[MAX_EVENT_SIZE];
static struct k_work_delayable hal_radio_timer_work, ble_stack_work;
static struct k_work_delayable ble_stack_work;

#if defined(CONFIG_PM_DEVICE)
/* ST Proprietary extended event */
#define STM32_HCI_EXT_EVT 0x82
#define ACI_HAL_END_OF_RADIO_ACTIVITY_VSEVT_CODE 0x0004
#define STM32_STATE_ALL_BITMASK 0xFFFF
#define STM32_STATE_IDLE 0x00

struct bt_hci_ext_evt_hdr {
uint8_t type;
uint8_t evt;
uint16_t len;
uint16_t vs_code;
uint8_t last_state;
uint8_t next_state;
} __packed;
#endif /* CONFIG_PM_DEVICE */

static struct net_buf *get_rx(uint8_t *msg);
static PKA_HandleTypeDef hpka;

#if CONFIG_BT_EXT_ADV
#if defined(CONFIG_BT_EXT_ADV)
static uint32_t __noinit aci_adv_nwk_buffer[CFG_BLE_ADV_NWK_BUFFER_SIZE >> 2];
#endif /* CONFIG_BT_EXT_ADV */

Expand All @@ -77,6 +92,41 @@ int BLEPLAT_NvmGet(void)
return 0;
}

/* Inform Zephyr PM about wakeup event from radio */
static void register_radio_event(uint32_t time, bool unregister)
{
int64_t value_ms, ticks;
static struct pm_policy_event radio_evt;
static bool first_time = true;

if (unregister) {
if (!first_time) {
first_time = true;
pm_policy_event_unregister(&radio_evt);
}
} else {
value_ms = HAL_RADIO_TIMER_DiffSysTimeMs(time, HAL_RADIO_TIMER_GetCurrentSysTime());
ticks = k_ms_to_ticks_floor64(value_ms) + k_uptime_ticks();
if (first_time) {
pm_policy_event_register(&radio_evt, ticks);
first_time = false;
} else {
pm_policy_event_update(&radio_evt, ticks);
}
}
}

uint8_t BLEPLAT_SetRadioTimerValue(uint32_t Time, uint8_t EventType, uint8_t CalReq)
{
uint8_t retval;

retval = HAL_RADIO_TIMER_SetRadioTimerValue(Time, EventType, CalReq);
if (IS_ENABLED(CONFIG_PM_DEVICE)) {
register_radio_event(Time, false);
}
return retval;
}

static void blestack_process(struct k_work *work)
{
BLE_STACK_Tick();
Expand All @@ -85,11 +135,6 @@ static void blestack_process(struct k_work *work)
}
}

static void vtimer_process(struct k_work *work)
{
HAL_RADIO_TIMER_Tick();
}

/* "If, since the last power-on or reset, the Host has ever issued a legacy
* advertising command and then issues an extended advertising command, or
* has ever issued an extended advertising command and then issues a legacy
Expand Down Expand Up @@ -196,9 +241,22 @@ void send_event(uint8_t *buffer_out, uint16_t buffer_out_length, int8_t overflow

const struct device *dev = DEVICE_DT_GET(DT_DRV_INST(0));
struct hci_data *hci = dev->data;
/* Construct net_buf from event data */
struct net_buf *buf = get_rx(buffer_out);
struct net_buf *buf;

#if defined(CONFIG_PM_DEVICE)
struct bt_hci_ext_evt_hdr *vs_evt = (struct bt_hci_ext_evt_hdr *)(buffer_out);

if ((vs_evt->type == STM32_HCI_EXT_EVT) && (vs_evt->evt == BT_HCI_EVT_VENDOR)) {
if ((vs_evt->vs_code == ACI_HAL_END_OF_RADIO_ACTIVITY_VSEVT_CODE) &&
(vs_evt->next_state == STM32_STATE_IDLE)) {
register_radio_event(0, true);
}
return;
}
#endif /* CONFIG_PM_DEVICE */

/* Construct net_buf from event data */
buf = get_rx(buffer_out);
if (buf) {
/* Handle the received HCI data */
LOG_DBG("New event %p len %u type %u", buf, buf->len, buf->data[0]);
Expand All @@ -210,28 +268,13 @@ void send_event(uint8_t *buffer_out, uint16_t buffer_out_length, int8_t overflow

void HAL_RADIO_TIMER_TxRxWakeUpCallback(void)
{
k_work_schedule(&hal_radio_timer_work, K_NO_WAIT);
k_work_schedule(&ble_stack_work, K_NO_WAIT);
}

void HAL_RADIO_TIMER_CpuWakeUpCallback(void)
{
k_work_schedule(&hal_radio_timer_work, K_NO_WAIT);
k_work_schedule(&ble_stack_work, K_NO_WAIT);
}

void HAL_RADIO_TxRxCallback(uint32_t flags)
{
BLE_STACK_RadioHandler(flags);
k_work_schedule(&ble_stack_work, K_NO_WAIT);
k_work_schedule(&hal_radio_timer_work, K_NO_WAIT);
}

ISR_DIRECT_DECLARE(RADIO_TIMER_TXRX_WKUP_IRQHandler)
{
HAL_RADIO_TIMER_TXRX_WKUP_IRQHandler();
ISR_DIRECT_PM(); /* PM done after servicing interrupt for best latency */
return 1;
}

ISR_DIRECT_DECLARE(RADIO_TXRX_IRQHandler)
Expand All @@ -248,59 +291,56 @@ ISR_DIRECT_DECLARE(RADIO_TXRX_SEQ_IRQHandler)
return 1;
}

ISR_DIRECT_DECLARE(RADIO_TIMER_CPU_WKUP_IRQHandler)
{
HAL_RADIO_TIMER_TimeoutCallback();
HAL_RADIO_TIMER_CpuWakeUpCallback();
ISR_DIRECT_PM(); /* PM done after servicing interrupt for best latency */
return 1;
}

ISR_DIRECT_DECLARE(RADIO_TIMER_ERROR_IRQHandler)
{
volatile uint32_t debug_cmd;

BLUE->DEBUGCMDREG |= 1;
/* If the device is configured with CLK_SYS = 64MHz
* and BLE clock = 16MHz, a register read is necessary
* to ensure interrupt register is properly cleared
* due to AHB down converter latency
*/
debug_cmd = BLUE->DEBUGCMDREG;
LOG_ERR("Timer error");
ISR_DIRECT_PM(); /* PM done after servicing interrupt for best latency */
return 1;
}

/* Function called from PKA_IRQHandler() context. */
void PKAMGR_IRQCallback(void)
{
k_work_schedule(&ble_stack_work, K_NO_WAIT);
}

static int _PKA_IRQHandler(void *args)
static void _PKA_IRQHandler(void *args)
{
ARG_UNUSED(args);

HAL_PKA_IRQHandler(&hpka);
ISR_DIRECT_PM(); /* PM done after servicing interrupt for best latency */
return 1;
}

static void ble_isr_installer(void)
{
IRQ_DIRECT_CONNECT(RADIO_TIMER_TXRX_WKUP_IRQn, BLE_WKUP_PRIO,
RADIO_TIMER_TXRX_WKUP_IRQHandler, BLE_WKUP_FLAGS);
IRQ_DIRECT_CONNECT(RADIO_TXRX_IRQn, BLE_TX_RX_PRIO, RADIO_TXRX_IRQHandler, BLE_TX_RX_FLAGS);
IRQ_DIRECT_CONNECT(RADIO_TIMER_CPU_WKUP_IRQn, CPU_WKUP_PRIO,
RADIO_TIMER_CPU_WKUP_IRQHandler, CPU_WKUP_FLAGS);
IRQ_DIRECT_CONNECT(RADIO_TXRX_SEQ_IRQn, BLE_RXTX_SEQ_PRIO, RADIO_TXRX_SEQ_IRQHandler,
BLE_RXTX_SEQ_FLAGS);
IRQ_DIRECT_CONNECT(RADIO_TIMER_ERROR_IRQn, BLE_ERROR_PRIO, RADIO_TIMER_ERROR_IRQHandler,
BLE_ERROR_FLAGS);
IRQ_CONNECT(PKA_IRQn, PKA_PRIO, _PKA_IRQHandler, NULL, PKA_FLAGS);
}

#if defined(CONFIG_PM_DEVICE)
static int ble_pm_action(const struct device *dev,
enum pm_device_action action)
{
static uint32_t pka_cr_vr;

switch (action) {
case PM_DEVICE_ACTION_SUSPEND:
LL_PWR_EnableWU_EWBLE();
pka_cr_vr = PKA->CR;
/* TBD: Manage PKA save for WB06 & WB07 */
break;
case PM_DEVICE_ACTION_RESUME:
LL_PWR_DisableWU_EWBLE();
/* TBD: Manage PKA restore for WB06 & WB07 */
PKA->CLRFR = PKA_CLRFR_PROCENDFC | PKA_CLRFR_RAMERRFC | PKA_CLRFR_ADDRERRFC;
PKA->CR = pka_cr_vr;
irq_enable(RADIO_TXRX_IRQn);
irq_enable(RADIO_TXRX_SEQ_IRQn);
irq_enable(PKA_IRQn);
break;
default:
return -ENOTSUP;
}

return 0;
}
#endif /* CONFIG_PM_DEVICE */

static void rng_get_random(void *num, size_t size)
{
const struct device *dev = DEVICE_DT_GET(DT_DRV_INST(0));
Expand Down Expand Up @@ -449,7 +489,6 @@ static int bt_hci_stm32wb0_send(const struct device *dev, struct net_buf *buf)
static int bt_hci_stm32wb0_open(const struct device *dev, bt_hci_recv_t recv)
{
struct hci_data *data = dev->data;
RADIO_TIMER_InitTypeDef VTIMER_InitStruct = {MAX_HS_STARTUP_TIME, 0, 0};
RADIO_HandleTypeDef hradio = {0};
BLE_STACK_InitTypeDef BLE_STACK_InitParams = {
.BLEStartRamAddress = (uint8_t *)dyn_alloc_a,
Expand Down Expand Up @@ -486,8 +525,6 @@ static int bt_hci_stm32wb0_open(const struct device *dev, bt_hci_recv_t recv)
ble_isr_installer();
hradio.Instance = RADIO;
HAL_RADIO_Init(&hradio);
HAL_RADIO_TIMER_Init(&VTIMER_InitStruct);

HW_AES_Init();
hpka.Instance = PKA;
HAL_PKA_Init(&hpka);
Expand All @@ -497,14 +534,15 @@ static int bt_hci_stm32wb0_open(const struct device *dev, bt_hci_recv_t recv)
return -EIO;
}

#if CONFIG_BT_EXT_ADV
#if defined(CONFIG_BT_EXT_ADV)
dm_init(CFG_BLE_ADV_NWK_BUFFER_SIZE, aci_adv_nwk_buffer);
#endif /* CONFIG_BT_EXT_ADV */

aci_adv_nwk_init();

#if defined(CONFIG_PM_DEVICE)
aci_hal_set_radio_activity_mask(STM32_STATE_ALL_BITMASK);
#endif /* CONFIG_PM_DEVICE */
data->recv = recv;
k_work_init_delayable(&hal_radio_timer_work, vtimer_process);
k_work_init_delayable(&ble_stack_work, blestack_process);
k_work_schedule(&ble_stack_work, K_NO_WAIT);

Expand All @@ -517,9 +555,10 @@ static DEVICE_API(bt_hci, drv) = {
};

#define HCI_DEVICE_INIT(inst) \
PM_DEVICE_DT_INST_DEFINE(inst, ble_pm_action); \
static struct hci_data hci_data_##inst = { \
}; \
DEVICE_DT_INST_DEFINE(inst, NULL, NULL, &hci_data_##inst, NULL, \
DEVICE_DT_INST_DEFINE(inst, NULL, PM_DEVICE_DT_INST_GET(inst), &hci_data_##inst, NULL, \
POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &drv)

/* Only one instance supported */
Expand Down
Loading