The PWM example in nRF5x SDK
(located in nRF5x_SDK_11.0.0\examples\peripheral\pwm_library)
has 2 insufficiency that if you follow SDK example totally:
1.the nRF51 is only able to control two channel PWM with BLE, or the BLE and PWM would be disorderd.
2.the example is not enable to start BLE at the same time
Board : nRF51822 / pca10028
the following example is how to control 4 channel PWM with UART and enable BLE
STEP 0. initial UART
Please follow this article:
http://gaiger-programming.blogspot.tw/2016/12/nrf51-make-printf-works-well.html?m=0
STEP 1. initial PWM
add this in Keil project setting
and include these files
add this in main.c
#include "app_pwm.h"
and change your BLE device name
#define DEVICE_NAME "PWM Peripheral"
STEP 3. enable PWM timers
one timer can only use 2 channel PWM as the SDK's restriction , besides, TIMER0 has been used by Softdevice to maintain scheduler.
so you have to enable TIMER1 and TIMER2
if I use TIMER0, the Softdevice would not work normally.
if the PWM channel number is over 2, the BLE and PWM would be disorderd
in "nrf_drv_config.h"
you will see about line 60
#define TIMER1_ENABLED 0
and about line 70
#define TIMER2_ENABLED 0
change as
//for pwm //#define TIMER1_ENABLED 0 #define TIMER1_ENABLED 1 //#define TIMER2_ENABLED 0 #define TIMER2_ENABLED 1
STEP 4. add PWM initial functions in main.c
about line 100
APP_PWM_INSTANCE(PWM1,1); APP_PWM_INSTANCE(PWM2,2); APP_TIMER_DEF(m_pwm1_timer_id); #define PWM1_TIMEOUT_INTERVAL APP_TIMER_TICKS(50, APP_TIMER_PRESCALER) APP_TIMER_DEF(m_pwm2_timer_id); #define PWM2_TIMEOUT_INTERVAL APP_TIMER_TICKS(50, APP_TIMER_PRESCALER)
static uint8_t led_1_value = 0; static uint8_t led_2_value = 0; static uint8_t led_3_value = 0; static uint8_t led_4_value = 0;
static volatile bool ready_flag;
void pwm_ready_callback(uint32_t pwm_id) { ready_flag = true; }
in main function
app_pwm_config_t pwm1_cfg = APP_PWM_DEFAULT_CONFIG_2CH(2000L, LED_1, LED_2); pwm1_cfg.pin_polarity[1] = APP_PWM_POLARITY_ACTIVE_LOW; err_code = app_pwm_init(&PWM1,&pwm1_cfg,pwm_ready_callback); APP_ERROR_CHECK(err_code); app_pwm_enable(&PWM1); app_pwm_config_t pwm2_cfg = APP_PWM_DEFAULT_CONFIG_2CH(2000L, LED_3, LED_4); pwm2_cfg.pin_polarity[0] = APP_PWM_POLARITY_ACTIVE_LOW; err_code = app_pwm_init(&PWM2,&pwm2_cfg,pwm_ready_callback); APP_ERROR_CHECK(err_code); app_pwm_enable(&PWM2);
STEP 5. add app_timer for pwm
static void pwm1_timeout_handler(void * p_context) { UNUSED_PARAMETER(p_context); ready_flag = false; while (app_pwm_channel_duty_set(&PWM1, 0, led_1_value) == NRF_ERROR_BUSY); while (app_pwm_channel_duty_set(&PWM1, 1, led_2_value) == NRF_ERROR_BUSY); } static void pwm2_timeout_handler(void * p_context) { UNUSED_PARAMETER(p_context); ready_flag = false; while (app_pwm_channel_duty_set(&PWM2, 0, led_3_value) == NRF_ERROR_BUSY); while (app_pwm_channel_duty_set(&PWM2, 1, led_4_value) == NRF_ERROR_BUSY); } static void timers_init(void) { // Initialize timer module. APP_TIMER_INIT(APP_TIMER_PRESCALER, APP_TIMER_OP_QUEUE_SIZE, false); /*agatha : add from here*/ uint32_t err_code; err_code = app_timer_create(&m_pwm1_timer_id,
APP_TIMER_MODE_SINGLE_SHOT,
pwm1_timeout_handler); APP_ERROR_CHECK(err_code); err_code = app_timer_create(&m_pwm2_timer_id,
APP_TIMER_MODE_SINGLE_SHOT,
pwm2_timeout_handler); APP_ERROR_CHECK(err_code); }
STEP 6. add command analyzed function in uart_event_handle
here is my command format (in hex)
0x40 0x01 value1 0x02 value2 0x03 value3 0x04 value4 0x23
for example,if I send :
40 01 ff 02 ff 03 ff 04 ff 23
than 4 channel PWM will be 100% (the max value of PWM)
add above uart_event_handle
static uint8_t data_array[255]; static uint8_t index;
and this is my uart_event_handle
void uart_event_handle(app_uart_evt_t * p_event) { uint32_t err_code; switch (p_event->evt_type) { case APP_UART_DATA_READY: UNUSED_VARIABLE(app_uart_get(&data_array[index])); index++; printf("uart event\r\n"); if (((0x40 == data_array[0] && 0x23 == data_array[index-1])) { for (uint8_t i = 0;i < index;i++) app_uart_put(data_array[i]); led_1_value = data_array[2]*0x64/0xff; led_2_value = data_array[4]*0x64/0xff; err_code = app_timer_start(m_pwm1_timer_id,PWM1_TIMEOUT_INTERVAL,NULL); APP_ERROR_CHECK(err_code); led_3_value = data_array[6]*0x64/0xff; led_4_value = data_array[8]*0x64/0xff; err_code = app_timer_start(m_pwm2_timer_id,PWM2_TIMEOUT_INTERVAL,NULL); APP_ERROR_CHECK(err_code); memset(&data_array,0,sizeof(data_array)); index = 0; } break; case APP_UART_COMMUNICATION_ERROR: APP_ERROR_HANDLER(p_event->data.error_communication); break; case APP_UART_FIFO_ERROR: APP_ERROR_HANDLER(p_event->data.error_code); break; default: break; } }
STEP 7. test device BLE advertisement by your smart phone
STEP 8. Test PWM function
open your serial tool ( I use sscom)
first command I send in hex
and the second command
and you can see the different PWM of your LEDs
reference:
https://github.com/electronut/nRF51-RGB-LED-test
沒有留言:
張貼留言