/* * Main firmware program for the sysmocom rfdsatt-4ch (RF digital step attenuator; 4 channel) * * Copyright (C) 2021 Harald Welte * * This library is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "attenuator.h" #include "misc.h" static uint32_t last_reset_cause; extern const struct attenuator_cfg board_att_cfg; extern struct attenuator_state *board_att_st[]; /* busy wait specified number of ms */ void msleep(uint32_t delay) { uint32_t wake = time_now() + delay; do { } while (wake > time_now()); } /*********************************************************************** * hardware initialization ***********************************************************************/ static void clock_setup(void) { rcc_clock_setup_pll(&rcc_hsi_configs[RCC_CLOCK_HSI_48MHZ]); /* HCLK=48MHz; ADC=6MHz; APB1=24MHz; APB2=48MHz; USB=48MHz */ /* tick rate of 1ms */ /* Enable GPIOC clock. */ rcc_periph_clock_enable(RCC_GPIOA); rcc_periph_clock_enable(RCC_GPIOB); rcc_periph_clock_enable(RCC_GPIOC); /* Enable clocks for USARTs */ rcc_periph_clock_enable(RCC_USART1); rcc_periph_clock_enable(RCC_USART2); } static void i2c_setup(void) { rcc_periph_clock_enable(RCC_I2C1); #ifdef STM32F1 gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_OPENDRAIN, GPIO_I2C1_SCL | GPIO_I2C1_SDA); #else gpio_set_af(GPIOB, GPIO_AF1, GPIO8 | GPIO9); #endif /* disable before making config changes */ i2c_peripheral_disable(I2C1); #ifdef STM32F1 /* APB1 runs at 24 MHz */ i2c_set_clock_frequency(I2C1, 24); #endif /* 400 kHz fast mode I2C */ i2c_set_speed(I2C1, i2c_speed_fm_400k, 24); //... i2c_peripheral_enable(I2C1); } static void usart_setup(void) { /* USART1: connected to debug header */ /* Setup GPIO pin GPIO_USART1_TX. */ #ifdef STM32F1 gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO_USART1_TX); #else gpio_set_af(GPIOA, GPIO_AF1, GPIO9 | GPIO10); #endif /* Setup UART parameters. */ usart_set_baudrate(USART1, 115200); usart_set_databits(USART1, 8); usart_set_stopbits(USART1, USART_STOPBITS_1); usart_set_mode(USART1, USART_MODE_TX_RX); usart_set_parity(USART1, USART_PARITY_NONE); usart_set_flow_control(USART1, USART_FLOWCONTROL_NONE); /* Finally enable the USART. */ usart_enable(USART1); /* USART2: connected to 2.5mm stereo jack */ /* Setup GPIO pin GPIO_USART2_TX. */ #ifdef STM32F1 gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO_USART2_TX); #else gpio_set_af(GPIOA, GPIO_AF1, GPIO2 | GPIO13); #endif /* Setup UART parameters. */ usart_set_baudrate(USART2, 115200); usart_set_databits(USART2, 8); usart_set_stopbits(USART2, USART_STOPBITS_1); usart_set_mode(USART2, USART_MODE_TX_RX); usart_set_parity(USART2, USART_PARITY_NONE); usart_set_flow_control(USART2, USART_FLOWCONTROL_NONE); /* Finally enable the USART. */ usart_enable(USART2); } static void gpio_setup(void) { #ifdef STM32F1 /* Set GPIO15 (in GPIO port B) to 'output push-pull'. */ gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO15); #else gpio_mode_setup(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO15); #endif } /*********************************************************************** * uVTY interface ***********************************************************************/ DEFUN(reset, reset_cmd, "reset", "Reset the board") { scb_reset_system(); } DEFUN(uuid, uuid_cmd, "uuid", "Get the unique ID") { char uuid[4*3*2+1]; desig_get_unique_id_as_string(uuid, sizeof(uuid)); printf("UUID: %s\r\n", uuid); } DEFUN(version, version_cmd, "version", "Get the firmware version") { printf("Firmware Version: %s\r\n", GIT_VERSION); } DEFUN(att_set, att_set_cmd, "attenuator-set", "Set an attenuator (channel, stage, dB)") { int channel, stage, dB; int rc; if (argc < 3) { printf("You muts specify three arguments (channel, stage, db)\r\n"); return; } channel = atoi(argv[1]); stage = atoi(argv[2]); dB = atoi(argv[3]); printf("Setting attenuator channel %d stage %d to %d dB...\r\n", channel, stage, dB); rc = attenuator_set(channel, stage, dB*4); if (rc < 0) printf("Error setting attenuator: %d\r\n", rc); } /*********************************************************************** * main ***********************************************************************/ static void print_banner(void) { char uuid[4*3*2+1]; desig_get_unique_id_as_string(uuid, sizeof(uuid)); printf("\r\n======================================================================\r\n"); printf("sysmocom RFDSATT main (build %s)\r\n", GIT_VERSION); printf("UUID: %s\r\n", uuid); printf("Reset cause(s): 0x%08lx\r\n", last_reset_cause); printf("======================================================================\r\n\r\n"); } int main(void) { /* get, store and clear the cause of the last reset */ last_reset_cause = RCC_CSR & RCC_CSR_RESET_FLAGS; RCC_CSR |= RCC_CSR_RMVF; clock_setup(); gpio_setup(); usart_setup(); iob_init(USART2); i2c_setup(); attenuator_init(&board_att_cfg, board_att_st); microvty_init("rfdsat4ch> "); microvty_register(&reset_cmd); microvty_register(&uuid_cmd); microvty_register(&version_cmd); microvty_register(&att_set_cmd); print_banner(); microvty_print_prompt(); /* Blink the LED (PB15) on the board with every transmitted byte. */ while (1) { int i; gpio_toggle(GPIOB, GPIO15); /* LED on/off */ //printf("Hello world\r\n"); microvty_try_recv(); for (i = 0; i < 800000; i++) /* Wait a bit. */ __asm__("nop"); } return 0; }