From 9b21fe50dbf9a4117b4d66c5d2b26097bd0863e8 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 28 Mar 2021 12:14:44 +0200 Subject: [PATCH] WIP: add librfn --- .gitignore | 7 ++ .gitmodules | 3 + librfn | 1 + mk/librfn.mk | 17 +++ projects/rfdsatt/Makefile | 1 + projects/rfdsatt/attenuator.c | 152 +++++++++++++++++++++++++++ projects/rfdsatt/attenuator.h | 45 ++++++++ projects/rfdsatt/board_rfdsatt_4ch.c | 47 +++++++++ projects/rfdsatt/misc.h | 5 + projects/rfdsatt/utils.h | 6 ++ projects/rules.mk | 4 +- 11 files changed, 286 insertions(+), 2 deletions(-) create mode 100644 .gitignore create mode 160000 librfn create mode 100644 mk/librfn.mk create mode 100644 projects/rfdsatt/attenuator.c create mode 100644 projects/rfdsatt/attenuator.h create mode 100644 projects/rfdsatt/board_rfdsatt_4ch.c create mode 100644 projects/rfdsatt/misc.h create mode 100644 projects/rfdsatt/utils.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d987cc2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +*.d +*.o + +*.map +*.elf +*.bin +*.srec diff --git a/.gitmodules b/.gitmodules index f996225..d1a282c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -2,3 +2,6 @@ path = libopencm3 url = https://github.com/libopencm3/libopencm3.git branch = master +[submodule "librfn"] + path = librfn + url = https://github.com/daniel-thompson/librfn.git diff --git a/librfn b/librfn new file mode 160000 index 0000000..80f85d0 --- /dev/null +++ b/librfn @@ -0,0 +1 @@ +Subproject commit 80f85d0325ced8ab56887afa567c2449ab5f2320 diff --git a/mk/librfn.mk b/mk/librfn.mk new file mode 100644 index 0000000..65fadfc --- /dev/null +++ b/mk/librfn.mk @@ -0,0 +1,17 @@ +-include $(OBJS:.o=.d) + +LIBRFN_DIR = ../../librfn + +ifeq ($(V),1) +$(info Using $(LIBRFN_DIR) path to librfn library) +endif + +OBJS += \ + ringbuf.o + +vpath %.c $(LIBRFN_DIR)/librfn +vpath %.c $(LIBRFN_DIR)/librfn/libopencm3 + +CPPFLAGS += -DNDEBUG +CPPFLAGS += -DCONFIG_CONSOLE_FROM_ISR=1 +CPPFLAGS += -I$(LIBRFN_DIR)/include diff --git a/projects/rfdsatt/Makefile b/projects/rfdsatt/Makefile index 29ab0ba..db900bb 100644 --- a/projects/rfdsatt/Makefile +++ b/projects/rfdsatt/Makefile @@ -38,4 +38,5 @@ OOCD_TARGET ?= stm32f1x all: elf bin srec +include ../../mk/librfn.mk include ../rules.mk diff --git a/projects/rfdsatt/attenuator.c b/projects/rfdsatt/attenuator.c new file mode 100644 index 0000000..5a45bea --- /dev/null +++ b/projects/rfdsatt/attenuator.c @@ -0,0 +1,152 @@ +/* Code to control digital step attenuators of the sysmocom RFDN board + * (C) 2017 by Harald Welte + */ +#include +#include +#include +#include + +#include "attenuator.h" +#include "utils.h" + +static const struct attenuator_cfg *g_att_cfg; +static struct attenuator_state **g_att_state; + +static void delay() +{ + volatile uint32_t i; + for (i = 0; i < 10000; i++) { } +} + +/* create a positive pulse on a given GPIO line */ +static void gpio_pulse(uint32_t bank, uint32_t nr) +{ + gpio_set(bank, nr); + /* FIXME: Some delay, 30ns for LE or CLK */ + delay(); + gpio_clear(bank, nr); +} + +/* set the data line to high or low */ +static void gpio_set_data(int high) +{ + if (high) + gpio_set(g_att_cfg->gpio_data.bank, g_att_cfg->gpio_data.gpio_nr); + else + gpio_clear(g_att_cfg->gpio_data.bank, g_att_cfg->gpio_data.gpio_nr); +} + +/* pulse the clock line with one positive pulse */ +static void gpio_pulse_clk(void) +{ + gpio_pulse(g_att_cfg->gpio_clock.bank, g_att_cfg->gpio_clock.gpio_nr); +} + +/* set a given attenuator to a given value + * \param channel The RF channel (0..7) + * \param stage Attenuator stage (0..1) + * \param value in quarter-dB (0..124) + */ +int attenuator_set(uint8_t channel, uint8_t stage, uint8_t val_qdb) +{ + uint8_t val = val_qdb/4; /* whole dB for this attenuator */ + const struct attenuator_def *ad; + int i; + + if (!g_att_cfg) + return -ENODEV; + + if (channel >= g_att_cfg->num_channels) + return -ENODEV; + + if (stage >= g_att_cfg->channels[channel].num_stages) + return -ENODEV; + + ad = &g_att_cfg->channels[channel].stage[stage]; + + if (val > 0x1f) + return -ERANGE; + + /* The shift register should be loaded while LE is held low to + * prevent the attenuator value from changing as data is + * entered */ + for (i = 5; i >= 0; i--) { + unsigned int bit = ((val >> i) & 1); + gpio_set_data(bit); + gpio_pulse_clk(); + } + + /* The LE input should then be toggled HIGH and brought LOW + * again, latching the new data. Minimum LE pulse width is 30ns */ + gpio_pulse(ad->le.bank, ad->le.gpio_nr); + + /* actual value we have set may not be exactly what was requested */ + g_att_state[channel][stage].value_qdB.current = val*4; + + return 0; +} + +/* get current attenuator value in quarter-dB */ +int attenuator_get(uint8_t channel, uint8_t stage, enum attenuator_value av) +{ + if (!g_att_cfg) + return -ENODEV; + + if (channel >= g_att_cfg->num_channels) + return -ENODEV; + + if (stage >= g_att_cfg->channels[channel].num_stages) + return -ENODEV; + + switch (av) { + case ATT_VAL_CURRENT: + return g_att_state[channel][stage].value_qdB.current; + case ATT_VAL_STARTUP: + return g_att_state[channel][stage].value_qdB.startup; + default: + return -EINVAL; + } +} + +/* initialize the attenuator driver */ +void attenuator_init(const struct attenuator_cfg *cfg, + struct attenuator_state **state) +{ + uint32_t banks[6] = { GPIOA, GPIOB, GPIOC, GPIOD, GPIOE, GPIOF }; + const uint32_t periph[6] = { RCC_GPIOA, RCC_GPIOB, RCC_GPIOC, + RCC_GPIOD, RCC_GPIOE, RCC_GPIOF }; + uint32_t pins[6] = {0, 0, 0, 0, 0, 0}; + unsigned int i, j, k; + + g_att_cfg = cfg; + g_att_state = state; + + /* collect the bit mask of all LE pins for each bank */ + for (i = 0; i < g_att_cfg->num_channels; i++) { + const struct attenuator_channel_def *ch = &g_att_cfg->channels[i]; + for (j = 0; j < ch->num_stages; j++) { + const struct attenuator_def *at = &ch->stage[j]; + for (k = 0; k < ARRAY_SIZE(banks); k++) { + if (at->le.bank != banks[k]) + continue; + pins[k] |= at->le.gpio_nr; + } + } + } + + /* add the shared DATA / CLOCK pins */ + for (k = 0; k < ARRAY_SIZE(banks); k++) { + if (g_att_cfg->gpio_clock.bank == banks[k]) + pins[k] |= g_att_cfg->gpio_clock.gpio_nr; + if (g_att_cfg->gpio_data.bank == banks[k]) + pins[k] |= g_att_cfg->gpio_data.gpio_nr; + } + + /* configure the GPIO of each bank based on he collected pin-bitmasks */ + for (k = 0; k < ARRAY_SIZE(banks); k++) { + if (!pins[k]) + continue; + rcc_periph_clock_enable(periph[k]); + gpio_set_mode(banks[k], GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, pins[k]); + } +} diff --git a/projects/rfdsatt/attenuator.h b/projects/rfdsatt/attenuator.h new file mode 100644 index 0000000..ec06505 --- /dev/null +++ b/projects/rfdsatt/attenuator.h @@ -0,0 +1,45 @@ +#pragma once +#include + +struct attenuator_gpio { + uint32_t bank; + uint32_t gpio_nr; +}; + + +/* definition o the Latch Enable line for one given Attenuator */ +struct attenuator_def { + struct attenuator_gpio le; +}; + +/* Our board has two attenuators in series for each RF channel */ +struct attenuator_channel_def { + const char *name; + unsigned int num_stages; + const struct attenuator_def *stage; +}; + +struct attenuator_cfg { + unsigned int num_channels; + const struct attenuator_channel_def *channels; + struct attenuator_gpio gpio_clock; + struct attenuator_gpio gpio_data; +}; + +enum attenuator_value { + ATT_VAL_CURRENT, + ATT_VAL_STARTUP +}; + +/* dynamic [runtime] state of one attenuator chip */ +struct attenuator_state { + struct { + uint8_t current; + uint8_t startup; + } value_qdB; +}; + +int attenuator_set(uint8_t channel, uint8_t stage, uint8_t val_qdb); +int attenuator_get(uint8_t channel, uint8_t stage, enum attenuator_value av); +void attenuator_init(const struct attenuator_cfg *cfg, + struct attenuator_state **state); diff --git a/projects/rfdsatt/board_rfdsatt_4ch.c b/projects/rfdsatt/board_rfdsatt_4ch.c new file mode 100644 index 0000000..70bbfa0 --- /dev/null +++ b/projects/rfdsatt/board_rfdsatt_4ch.c @@ -0,0 +1,47 @@ + +#include + +#include "attenuator.h" +#include "utils.h" + +#define NUM_CHAN 4 +#define NUM_STAGE 2 + +static const struct attenuator_def attenuator_def_at1[NUM_STAGE] = { + { { GPIOB, GPIO3 } }, { { GPIOA, GPIO15 } }, +}; +static const struct attenuator_def attenuator_def_at2[NUM_STAGE] = { + { { GPIOB, GPIO5 } }, { { GPIOB, GPIO4 } }, +}; +static const struct attenuator_def attenuator_def_at3[NUM_STAGE] = { + { { GPIOD, GPIO0 } }, { { GPIOD, GPIO1 } }, +}; +static const struct attenuator_def attenuator_def_at4[NUM_STAGE] = { + { { GPIOA, GPIO0 } }, { { GPIOA, GPIO1 } }, +}; +static struct attenuator_state attenuator_st_at1[NUM_STAGE]; +static struct attenuator_state attenuator_st_at2[NUM_STAGE]; +static struct attenuator_state attenuator_st_at3[NUM_STAGE]; +static struct attenuator_state attenuator_st_at4[NUM_STAGE]; + +/* LE definition of the Attenuator Channels, taken from schematics */ +static const struct attenuator_channel_def channels[NUM_CHAN] = { + [0] = { "AT1", ARRAY_SIZE(attenuator_def_at1), attenuator_def_at1 }, + [1] = { "AT2", ARRAY_SIZE(attenuator_def_at2), attenuator_def_at2 }, + [2] = { "AT3", ARRAY_SIZE(attenuator_def_at3), attenuator_def_at3 }, + [3] = { "AT4", ARRAY_SIZE(attenuator_def_at4), attenuator_def_at4 }, +}; + +const struct attenuator_cfg board_att_cfg = { + .num_channels = ARRAY_SIZE(channels), + .channels = channels, + .gpio_clock = { GPIOA, GPIO11 }, + .gpio_data = { GPIOA, GPIO12 }, +}; + +struct attenuator_state *board_att_st[NUM_CHAN] = { + [0] = attenuator_st_at1, + [1] = attenuator_st_at2, + [2] = attenuator_st_at3, + [3] = attenuator_st_at4, +}; diff --git a/projects/rfdsatt/misc.h b/projects/rfdsatt/misc.h new file mode 100644 index 0000000..382b615 --- /dev/null +++ b/projects/rfdsatt/misc.h @@ -0,0 +1,5 @@ +#pragma once + +#include + +extern void msleep(uint32_t delay); diff --git a/projects/rfdsatt/utils.h b/projects/rfdsatt/utils.h new file mode 100644 index 0000000..39db393 --- /dev/null +++ b/projects/rfdsatt/utils.h @@ -0,0 +1,6 @@ +#pragma once + +/*! Determine number of elements in an array of static size */ +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) +#endif diff --git a/projects/rules.mk b/projects/rules.mk index a63509b..67994ff 100644 --- a/projects/rules.mk +++ b/projects/rules.mk @@ -204,8 +204,8 @@ print-%: $(Q)$(LD) $(TGT_LDFLAGS) $(LDFLAGS) $(OBJS) $(LDLIBS) -o $(*).elf %.o: %.c - @#printf " CC $(*).c\n" - $(Q)$(CC) $(TGT_CFLAGS) $(CFLAGS) $(TGT_CPPFLAGS) $(CPPFLAGS) -o $(*).o -c $(*).c + #@printf " CC $(*).c\n" + $(Q)$(CC) $(TGT_CFLAGS) $(CFLAGS) $(TGT_CPPFLAGS) $(CPPFLAGS) -o $@ -c $< %.o: %.cxx @#printf " CXX $(*).cxx\n"