コンテンツにスキップ

#104 Angle Brick

Overview

ボリューム抵抗を使ったBrickです。

I/Oピンからアナログ値を取得することができます。

LED Brickの明るさを調節する際などに使用します。

Connecting

Schematic

Code explanation

nRF52832は、ADCが使えるピンは決まっており、P0.03は、AIN1となります。

アナログ値はターミナルソフト(Teratermなど)から確認しましょう。

ドライバはPPI(Programmable peripheral interconnect)ドライバを使います。A/D変換するの にARMコアを起動するのは消費電力の無駄であり、PPIという仕組みを利用して、PPIのチャンネルを指定 、コアを起動しないで、イベントメモリとタスクで計測データをPPIのメモリに保存します。

User Include Directories

Solution Option -> Preprocessor -> User Include Directoriesに以下を追加する。(../nRF5_SDKの部分は適宜変えてください。)

Path
../nRF5_SDK/modules/nrfx/drivers/src/prs
../nRF5_SDK/modules/nrfx/drivers/src
../nRF5_SDK/components/libraries/mutex
../nRF5_SDK/components/libraries/atomic
../nRF5_SDK/components/libraries/ringbuf
../nRF5_SDK/external/fprintf
../nRF5_SDK/components/libraries/strerror
../nRF5_SDK/components/libraries/balloc
../nRF5_SDK/components/libraries/memobj
../nRF5_SDK/components/libraries/log
../nRF5_SDK/components/libraries/experimental_section_vars
../nRF5_SDK/components/libraries/pwr_mgmt
../nRF5_SDK/components/libraries/delay
../nRF5_SDK/modules/nrfx/hal
../nRF5_SDK/components/boards
../nRF5_SDK/components/drivers_nrf/nrf_soc_nosd
../nRF5_SDK/components/libraries/util
../nRF5_SDK/integration/nrfx
../nRF5_SDK/modules/nrfx
../nRF5_SDK/modules/nrfx/drivers/include
../nRF5_SDK/integration/nrfx/legacy
../nRF5_SDK/components/toolchain/cmsis/include
../nRF5_SDK/modules/nrfx/mdk
.

Preprocessor Definitions

Solution Option -> Preprocessor -> Preprocessor Definitionsに以下を追加する。

COPT
SAADC_ENABLED
PPI_ENABLED
POWER_ENABLED
TIMER0_ENABLED
TIMER_ENABLED
NRFX_SAADC_ENABLED
NRFX_PPI_ENABLED
NRFX_POWER_ENABLED
NRFX_TIMER0_ENABLED
NRFX_TIMER_ENABLED
BOARD_CUSTOM
NRF52832_XXAB
DEBUG

SDK File

Projectに以下のファイルを追加する。(../nRF5_SDKの部分は適宜変えてください。)

File Path
app_error_handler_gcc.c ../nRF5_SDK/components/libraries/util
app_error_weak.c ../nRF5_SDK/components/libraries/util
app_error.c ../nRF5_SDK/components/libraries/util
app_util_platform.c ../nRF5_SDK/components/libraries/util
nrf_atomic.c ../nRF5_SDK/components/libraries/atomic
nrf_balloc.c ../nRF5_SDK/components/libraries/balloc
nrf_drv_power.c ../nRF5_SDK/integration/nrfx/legacy
nrf_drv_ppi.c ../nRF5_SDK/integration/nrfx/legacy
nrf_drv_uart.c ../nRF5_SDK/integration/nrfx/legacy
nrf_fprintf_format.c ../nRF5_SDK/external/fprintf
nrf_fprintf.c ../nRF5_SDK/external/fprintf
nrf_log_backend_serial.c ../nRF5_SDK/components/libraries/log/src
nrf_log_backend_uart.c ../nRF5_SDK/components/libraries/log/src
nrf_log_default_backends.c ../nRF5_SDK/components/libraries/log/src
nrf_log_frontend.c ../nRF5_SDK/components/libraries/log/src
nrf_log_str_formatter.c ../nRF5_SDK/components/libraries/log/src
nrf_memobj.c ../nRF5_SDK/components/libraries/memobj
nrf_pwr_mgmt.c ../nRF5_SDK/components/libraries/pwr_mgmt
nrf_ringbuf.c ../nRF5_SDK/components/libraries/ringbuf
nrf_section_iter.c ../nRF5_SDK/components/libraries/experimental_section_vars
nrf_strerror.c ../nRF5_SDK/components/libraries/strerror
nrfx_power.c ../nRF5_SDK/modules/nrfx/drivers/src
nrfx_ppi.c ../nRF5_SDK/modules/nrfx/drivers/src
nrfx_prs.c ../nRF5_SDK/modules/nrfx/drivers/src/prs
nrfx_saadc.c ../nRF5_SDK/modules/nrfx/drivers/src
nrfx_timer.c ../nRF5_SDK/modules/nrfx/drivers/src
nrfx_uart.c ../nRF5_SDK/modules/nrfx/drivers/src
nrfx_uarte.c ../nRF5_SDK/modules/nrfx/drivers/src

Section

SEGGER_Flash.icfファイルを編集する。(SEGGER_Flash.icfはProject配下に自動生成されている。以下抜粋)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
 :

define block log_const_data_start with size = 8 { symbol __start_log_const_data };
define block log_const_data_list { section .log_const_data* };
define block log_const_data_stop with size = 8 { symbol __stop_log_const_data };
define block log_const_data with fixed order { block log_const_data_start, block log_const_data_list, block log_const_data_stop };

 :

place in FLASH                           {
                                           block tdata_load,                       // Thread-local-storage load image
                                           section .log_backends,
                                           section .nrf_balloc,
                                           block log_const_data
                                         };
 :

IRQHandler

Cortex_M_Startup.sファイルを編集する。(長いので抜粋)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
ISR_HANDLER ExternalISR0
ISR_HANDLER ExternalISR1
ISR_HANDLER UARTE0_UART0_IRQHandler //ExternalISR2
ISR_HANDLER ExternalISR3
ISR_HANDLER ExternalISR4
ISR_HANDLER ExternalISR5
ISR_HANDLER ExternalISR6
ISR_HANDLER SAADC_IRQHandler        //ExternalISR7
ISR_HANDLER ExternalISR8
ISR_HANDLER ExternalISR9
ISR_HANDLER ExternalISR10

Sample Code

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "nrf.h"
#include "nrf_drv_saadc.h"
#include "nrf_drv_ppi.h"
#include "nrf_drv_timer.h"
#include "boards.h"
#include "app_error.h"
#include "nrf_delay.h"
#include "app_util_platform.h"
#include "nrf_pwr_mgmt.h"
#include "nrf_drv_power.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"
#define NRF_LOG_MODULE_NAME FABO_104_ANGLE
#include "nrf_log.h"
NRF_LOG_MODULE_REGISTER();

#define SAMPLES_IN_BUFFER 10
volatile uint8_t state = 1;

static const nrf_drv_timer_t m_timer = NRF_DRV_TIMER_INSTANCE(0);
static nrf_saadc_value_t     m_buffer_pool[2][SAMPLES_IN_BUFFER];
static nrf_ppi_channel_t     m_ppi_channel;
static uint32_t              m_adc_evt_counter;

nrf_log_module_const_data_t*    __start_log_const_data;
nrf_log_module_dynamic_data_t*  __start_log_dynamic_data;
void*                           __start_pwr_mgmt_data;
void*                           __stop_log_const_data;
void*                           __stop_log_dynamic_data;
void*                           __stop_pwr_mgmt_data;

void timer_handler(nrf_timer_event_t event_type, void * p_context)
{

}

void saadc_sampling_event_init(void)
{
    ret_code_t err_code;

    err_code = nrf_drv_ppi_init();
    APP_ERROR_CHECK(err_code);

    nrf_drv_timer_config_t timer_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG;
    timer_cfg.bit_width = NRF_TIMER_BIT_WIDTH_32;
    err_code = nrf_drv_timer_init(&m_timer, &timer_cfg, timer_handler);
    APP_ERROR_CHECK(err_code);

    uint32_t ticks = nrf_drv_timer_ms_to_ticks(&m_timer, 100);
    nrf_drv_timer_extended_compare(&m_timer,
                                   NRF_TIMER_CC_CHANNEL0,
                                   ticks,
                                   NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK,
                                   false);
    nrf_drv_timer_enable(&m_timer);

    uint32_t timer_compare_event_addr = nrf_drv_timer_compare_event_address_get(&m_timer,
                                                                                NRF_TIMER_CC_CHANNEL0);
    uint32_t saadc_sample_task_addr   = nrf_drv_saadc_sample_task_get();

    /* setup ppi channel so that timer compare event is triggering sample task in SAADC */
    err_code = nrf_drv_ppi_channel_alloc(&m_ppi_channel);
    APP_ERROR_CHECK(err_code);

    err_code = nrf_drv_ppi_channel_assign(m_ppi_channel,
                                          timer_compare_event_addr,
                                          saadc_sample_task_addr);
    APP_ERROR_CHECK(err_code);
}


void saadc_sampling_event_enable(void)
{
    ret_code_t err_code = nrf_drv_ppi_channel_enable(m_ppi_channel);

    APP_ERROR_CHECK(err_code);
}


void saadc_callback(nrf_drv_saadc_evt_t const * p_event)
{
    if (p_event->type == NRF_DRV_SAADC_EVT_DONE)
    {
        ret_code_t err_code;

        err_code = nrf_drv_saadc_buffer_convert(p_event->data.done.p_buffer, SAMPLES_IN_BUFFER);
        APP_ERROR_CHECK(err_code);

        int i;
        NRF_LOG_INFO("ADC event number: %d", (int)m_adc_evt_counter);

        for (i = 0; i < SAMPLES_IN_BUFFER; i++)
        {
            NRF_LOG_INFO("%d", p_event->data.done.p_buffer[i]);
        }
        m_adc_evt_counter++;
    }
}


void saadc_init(void)
{
    ret_code_t err_code;
    nrf_saadc_channel_config_t channel_config =
        NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN1);

    err_code = nrf_drv_saadc_init(NULL, saadc_callback);
    APP_ERROR_CHECK(err_code);

    err_code = nrf_drv_saadc_channel_init(0, &channel_config);
    APP_ERROR_CHECK(err_code);

    err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool[0], SAMPLES_IN_BUFFER);
    APP_ERROR_CHECK(err_code);

    err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool[1], SAMPLES_IN_BUFFER);
    APP_ERROR_CHECK(err_code);

}

int main(void)
{
    APP_ERROR_CHECK(NRF_LOG_INIT(NULL));
    NRF_LOG_DEFAULT_BACKENDS_INIT();

    APP_ERROR_CHECK(nrf_drv_power_init(NULL));

    APP_ERROR_CHECK(nrf_pwr_mgmt_init());

    NRF_LOG_INFO("Fabo Shinobi Sample Angle Brick 104");

    saadc_init();
    saadc_sampling_event_init();
    saadc_sampling_event_enable();

    while (1)
    {
        nrf_pwr_mgmt_run();
        NRF_LOG_FLUSH();
    }
}

構成Parts

  • ボリューム抵抗器A 10k

GitHub