BWP-WS19-02/Implementierungsdetails: Unterschied zwischen den Versionen

Aus Verteilte Systeme - Wiki
Zur Navigation springen Zur Suche springen
Zeile 1: Zeile 1:
==Implementierung des Counters==
 
 
Um externe Impulse der rotary-encoder und des solar-click Ladereglers ohne CPU zählen zu können sollen IC interne Counter verwendet werden.
 
Beim verwendeten feather-board sind diese counter unter der Kategorie timer/counter zu finden.
 
Es gibt keine expliziten Counter. Die Timer inkrementieren per Default über einen angeschlossenen Takt (Wahlweise 1MHz oder 16MHz).
 
Über ein MODE Bit kann der Time als Counter fungieren:
 
 
[[Datei: Timer_counter.png|Timer_counter.png|600px]]
 
 
Kapitel 24 TIMER — Timer/counter - nRF52832_PS_v1.4.pdf
 
 
 
===Linksammlung zum Thema Counter===
 
 
Da sich derzeit sowohl das Antriebs- als auch Energie- Team mit dem Counter beschäftigt folgt hier eine Linksammlung mit vermutlich relevanten Dateien:
 
 
 
'''default MODE'''
 
 
bwp_ws19/modules/hal/nordic/nrfx_config_nrf52832.h:#define NRFX_TIMER_DEFAULT_CONFIG_MODE 0
 
 
'''driver'''
 
 
bwp_ws19/zephyr/drivers/counter/counter_nrfx_timer.c
 
 
<source lang="c">
 
#define COUNTER_NRFX_TIMER_DEVICE(idx) \
 
BUILD_ASSERT_MSG(DT_NORDIC_NRF_TIMER_TIMER_##idx##_PRESCALER <= \
 
TIMER_PRESCALER_PRESCALER_Msk, \
 
"TIMER prescaler out of range"); \
 
DEVICE_DECLARE(timer_##idx); \
 
static int counter_##idx##_init(struct device *dev) \
 
{ \
 
IRQ_CONNECT(DT_NORDIC_NRF_TIMER_TIMER_##idx##_IRQ_0, \
 
DT_NORDIC_NRF_TIMER_TIMER_##idx##_IRQ_0_PRIORITY, \
 
irq_handler, DEVICE_GET(timer_##idx), 0); \
 
static const struct counter_timer_config config = { \
 
.freq = DT_NORDIC_NRF_TIMER_TIMER_##idx##_PRESCALER, \
 
.mode = NRF_TIMER_MODE_TIMER, \
 
.bit_width = (TIMER##idx##_MAX_SIZE == 32) ? \
 
NRF_TIMER_BIT_WIDTH_32 : \
 
NRF_TIMER_BIT_WIDTH_16, \
 
}; \
 
return init_timer(dev, &config); \
 
} \
 
static struct counter_nrfx_data counter_##idx##_data; \
 
static struct counter_nrfx_ch_data \
 
counter##idx##_ch_data[CC_TO_ID(TIMER##idx##_CC_NUM)]; \
 
LOG_INSTANCE_REGISTER(LOG_MODULE_NAME, idx, CONFIG_COUNTER_LOG_LEVEL); \
 
static const struct counter_nrfx_config nrfx_counter_##idx##_config = {\
 
.info = { \
 
.max_top_value = (TIMER##idx##_MAX_SIZE == 32) ? \
 
0xffffffff : 0x0000ffff, \
 
.freq = TIMER_CLOCK / \
 
(1 << DT_NORDIC_NRF_TIMER_TIMER_##idx##_PRESCALER), \
 
.flags = COUNTER_CONFIG_INFO_COUNT_UP, \
 
.channels = CC_TO_ID(TIMER##idx##_CC_NUM), \
 
}, \
 
.ch_data = counter##idx##_ch_data, \
 
.timer = NRF_TIMER##idx, \
 
LOG_INSTANCE_PTR_INIT(log, LOG_MODULE_NAME, idx) \
 
}; \
 
DEVICE_AND_API_INIT(timer_##idx, \
 
DT_NORDIC_NRF_TIMER_TIMER_##idx##_LABEL, \
 
counter_##idx##_init, \
 
&counter_##idx##_data, \
 
&nrfx_counter_##idx##_config.info, \
 
PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, \
 
&counter_nrfx_driver_api)
 
</source>
 
 
 
... ##idx## wurde durch 0 ersetzt. Ob das Sinn macht weiß ich nicht, aber jetzt kann man besser lesen was dieses Makro macht:
 
 
<source lang="c">
 
/* counter init function */
 
static int counter_0_init(struct device *dev)
 
{
 
IRQ_CONNECT(DT_NORDIC_NRF_TIMER_TIMER_0_IRQ_0,
 
DT_NORDIC_NRF_TIMER_TIMER_0_IRQ_0_PRIORITY,
 
irq_handler, DEVICE_GET(timer_0), 0);
 
 
static const struct counter_timer_config config = {
 
.freq = DT_NORDIC_NRF_TIMER_TIMER_0_PRESCALER,
 
.mode = NRF_TIMER_MODE_TIMER, //Hier müssen wir dann den Counter Mode einstellen
 
.bit_width = (TIMER0_MAX_SIZE == 32) ? NRF_TIMER_BIT_WIDTH_32 : NRF_TIMER_BIT_WIDTH_16,
 
};
 
 
return init_timer(dev, &config);
 
}
 
 
 
static struct counter_nrfx_data counter_idx_data;
 
static struct counter_nrfx_ch_data counter_idx_ch_data[CC_TO_ID(TIMER_0_CC_NUM)];
 
LOG_INSTANCE_REGISTER(LOG_MODULE_NAME, idx, CONFIG_COUNTER_LOG_LEVEL);
 
 
 
/* counter options */
 
static const struct counter_nrfx_config nrfx_counter_0_config = {
 
.info = {
 
.max_top_value = (TIMER_0_MAX_SIZE == 32) ? 0xffffffff : 0x0000ffff,
 
.freq = TIMER_CLOCK / (1 << DT_NORDIC_NRF_TIMER_TIMER_idx_PRESCALER),
 
.flags = COUNTER_CONFIG_INFO_COUNT_UP,
 
.channels = CC_TO_ID(TIMER_idx_CC_NUM),
 
},
 
.ch_data = counteridx_ch_data,
 
.timer = NRF_TIMER_idx,
 
LOG_INSTANCE_PTR_INIT(log, LOG_MODULE_NAME, idx)
 
};
 
 
/* Device and API init */
 
DEVICE_AND_API_INIT(timer_idx, DT_NORDIC_NRF_TIMER_TIMER_idx_LABEL, counter_idx_init,
 
&counter_idx_data, &nrfx_counter_idx_config.info, PRE_KERNEL_1,
 
CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &counter_nrfx_driver_api)
 
</source>
 
 
 
 
Jetzt können wir diese Structs zb im Programm
 
 
bwp_ws19/zephyr/samples/drivers/counter/alarm/src/main.c
 
 
einbinden, um einen counter zu initialisieren.
 
 
 
 
===PPI Programmable Peripheral Interconnect===
 
===PPI Programmable Peripheral Interconnect===
   
Zeile 136: Zeile 11:
   
 
bwp_ws19/modules/hal/nordic/nrfx/drivers/include/nrfx_ppi.h
 
bwp_ws19/modules/hal/nordic/nrfx/drivers/include/nrfx_ppi.h
  +
oder
  +
bwp_ws19/modules/lib/openthread/third_party/NordicSemiconductor/nrfx/drivers/include/nrfx_ppi.h
   
 
<source lang="c">
 
<source lang="c">
Zeile 164: Zeile 41:
 
</source>
 
</source>
   
  +
Die Implementierung der Funktionen findet sich in:
  +
bwp_ws19/modules/hal/nordic/nrfx/drivers/src/nrfx_ppi.c
  +
oder
  +
bwp_ws19/modules/lib/openthread/third_party/NordicSemiconductor/nrfx/drivers/src/nrfx_ppi.c
  +
  +
  +
In der Datei
  +
bwp_ws19/zephyr/drivers/counter/counter_nrfx_rtc.c
  +
werden diese Funktionen verwendet.
  +
  +
<source lang="C">
  +
(void)nrfx_ppi_channel_assign(data->ppi_ch, evt_addr, task_addr);
  +
(void)nrfx_ppi_channel_enable(data->ppi_ch);
  +
</source>
  +
  +
  +
  +
Auch die UART Ausgbe nutzt die diese Funktionen:
  +
bwp_ws19/zephyr/drivers/serial/uart_nrfx_uarte.c
  +
  +
<source lang="C">
  +
static int uarte_nrfx_rx_counting_init(struct device *dev)
  +
{
  +
struct uarte_nrfx_data *data = get_dev_data(dev);
  +
const struct uarte_nrfx_config *cfg = get_dev_config(dev);
  +
NRF_UARTE_Type *uarte = get_uarte_instance(dev);
  +
int ret;
  +
  +
if (hw_rx_counting_enabled(data)) {
  +
nrfx_timer_config_t tmr_config = NRFX_TIMER_DEFAULT_CONFIG;
  +
  +
tmr_config.mode = NRF_TIMER_MODE_COUNTER;
  +
tmr_config.bit_width = NRF_TIMER_BIT_WIDTH_32;
  +
ret = nrfx_timer_init(&cfg->timer,
  +
&tmr_config,
  +
timer_handler);
  +
if (ret != NRFX_SUCCESS) {
  +
LOG_ERR("Timer already initialized, "
  +
"switching to software byte counting.");
  +
data->async->hw_rx_counting = false;
  +
} else {
  +
nrfx_timer_enable(&cfg->timer);
  +
nrfx_timer_clear(&cfg->timer);
  +
}
  +
}
  +
  +
if (hw_rx_counting_enabled(data)) {
  +
ret = gppi_channel_alloc(&data->async->rx_cnt.ppi);
  +
if (ret != NRFX_SUCCESS) {
  +
LOG_ERR("Failed to allocate PPI Channel, "
  +
"switching to software byte counting.");
  +
data->async->hw_rx_counting = false;
  +
nrfx_timer_uninit(&cfg->timer);
  +
}
  +
}
  +
  +
if (hw_rx_counting_enabled(data)) {
  +
#if CONFIG_HAS_HW_NRF_PPI
  +
ret = nrfx_ppi_channel_assign(
  +
data->async->rx_cnt.ppi,
  +
nrf_uarte_event_address_get(uarte,
  +
NRF_UARTE_EVENT_RXDRDY),
  +
nrfx_timer_task_address_get(&cfg->timer,
  +
NRF_TIMER_TASK_COUNT));
  +
  +
if (ret != NRFX_SUCCESS) {
  +
return -EIO;
  +
}
  +
#else
  +
nrf_uarte_publish_set(uarte,
  +
NRF_UARTE_EVENT_RXDRDY,
  +
data->async->rx_cnt.ppi);
  +
nrf_timer_subscribe_set(cfg->timer.p_reg,
  +
NRF_TIMER_TASK_COUNT,
  +
data->async->rx_cnt.ppi);
  +
  +
#endif
  +
ret = gppi_channel_enable(data->async->rx_cnt.ppi);
  +
if (ret != NRFX_SUCCESS) {
  +
return -EIO;
  +
}
  +
} else {
  +
nrf_uarte_int_enable(uarte, NRF_UARTE_INT_RXDRDY_MASK);
  +
}
  +
  +
return 0;
  +
}
  +
</source>
   
 
...
 
...

Version vom 20. Dezember 2019, 23:39 Uhr

PPI Programmable Peripheral Interconnect

PPI.png

Kapitel 22 PPI — Programmable peripheral interconnect - nRF52832_PS_v1.4.pdf


Um das Peripheral "Event" (GPIO-Register) an die Peripheral "Task" Counter zu zu weisen suchen wir im Zephyr OS nach bereits bestehenden "event end point (EEP) and task end points (TEP)" um nicht die gleichen EEP und TEP zu verweden.

In der Datei nrfx_ppi.h sind die Funktionen deklariert die ein EEP und TEP definieren.

bwp_ws19/modules/hal/nordic/nrfx/drivers/include/nrfx_ppi.h oder bwp_ws19/modules/lib/openthread/third_party/NordicSemiconductor/nrfx/drivers/include/nrfx_ppi.h

/**
 * @brief Function for assigning task and event endpoints to the PPI channel.
 *
 * @param[in] channel PPI channel to be assigned endpoints.
 * @param[in] eep     Event endpoint address.
 * @param[in] tep     Task endpoint address.
 *
 * @retval NRFX_SUCCESS             The channel was successfully assigned.
 * @retval NRFX_ERROR_INVALID_STATE The channel is not allocated for the user.
 * @retval NRFX_ERROR_INVALID_PARAM The channel is not user-configurable.
 */
nrfx_err_t nrfx_ppi_channel_assign(nrf_ppi_channel_t channel, uint32_t eep, uint32_t tep);

/**
 * @brief Function for assigning fork endpoint to the PPI channel or clearing it.
 *
 * @param[in] channel  PPI channel to be assigned endpoints.
 * @param[in] fork_tep Fork task endpoint address or 0 to clear.
 *
 * @retval NRFX_SUCCESS             The channel was successfully assigned.
 * @retval NRFX_ERROR_INVALID_STATE The channel is not allocated for the user.
 * @retval NRFX_ERROR_NOT_SUPPORTED Function is not supported.
 */
nrfx_err_t nrfx_ppi_channel_fork_assign(nrf_ppi_channel_t channel, uint32_t fork_tep);

Die Implementierung der Funktionen findet sich in: bwp_ws19/modules/hal/nordic/nrfx/drivers/src/nrfx_ppi.c oder bwp_ws19/modules/lib/openthread/third_party/NordicSemiconductor/nrfx/drivers/src/nrfx_ppi.c


In der Datei bwp_ws19/zephyr/drivers/counter/counter_nrfx_rtc.c werden diese Funktionen verwendet.

	(void)nrfx_ppi_channel_assign(data->ppi_ch, evt_addr, task_addr);
	(void)nrfx_ppi_channel_enable(data->ppi_ch);


Auch die UART Ausgbe nutzt die diese Funktionen: bwp_ws19/zephyr/drivers/serial/uart_nrfx_uarte.c

static int uarte_nrfx_rx_counting_init(struct device *dev)
{
	struct uarte_nrfx_data *data = get_dev_data(dev);
	const struct uarte_nrfx_config *cfg = get_dev_config(dev);
	NRF_UARTE_Type *uarte = get_uarte_instance(dev);
	int ret;

	if (hw_rx_counting_enabled(data)) {
		nrfx_timer_config_t tmr_config = NRFX_TIMER_DEFAULT_CONFIG;

		tmr_config.mode = NRF_TIMER_MODE_COUNTER;
		tmr_config.bit_width = NRF_TIMER_BIT_WIDTH_32;
		ret = nrfx_timer_init(&cfg->timer,
				      &tmr_config,
				      timer_handler);
		if (ret != NRFX_SUCCESS) {
			LOG_ERR("Timer already initialized, "
				"switching to software byte counting.");
			data->async->hw_rx_counting = false;
		} else {
			nrfx_timer_enable(&cfg->timer);
			nrfx_timer_clear(&cfg->timer);
		}
	}

	if (hw_rx_counting_enabled(data)) {
		ret = gppi_channel_alloc(&data->async->rx_cnt.ppi);
		if (ret != NRFX_SUCCESS) {
			LOG_ERR("Failed to allocate PPI Channel, "
				"switching to software byte counting.");
			data->async->hw_rx_counting = false;
			nrfx_timer_uninit(&cfg->timer);
		}
	}

	if (hw_rx_counting_enabled(data)) {
#if CONFIG_HAS_HW_NRF_PPI
		ret = nrfx_ppi_channel_assign(
			data->async->rx_cnt.ppi,
			nrf_uarte_event_address_get(uarte,
						    NRF_UARTE_EVENT_RXDRDY),
			nrfx_timer_task_address_get(&cfg->timer,
						    NRF_TIMER_TASK_COUNT));

		if (ret != NRFX_SUCCESS) {
			return -EIO;
		}
#else
		nrf_uarte_publish_set(uarte,
				      NRF_UARTE_EVENT_RXDRDY,
				      data->async->rx_cnt.ppi);
		nrf_timer_subscribe_set(cfg->timer.p_reg,
					NRF_TIMER_TASK_COUNT,
					data->async->rx_cnt.ppi);

#endif
		ret = gppi_channel_enable(data->async->rx_cnt.ppi);
		if (ret != NRFX_SUCCESS) {
			return -EIO;
		}
	} else {
		nrf_uarte_int_enable(uarte, NRF_UARTE_INT_RXDRDY_MASK);
	}

	return 0;
}

...