v. 2.0.0 - new modems, FX.25 etc.pull/33/head
| @ -0,0 +1,3 @@ | |||
| [submodule "lwfec"] | |||
| path = lwfec | |||
| url = https://github.com/sq8vps/lwfec | |||
| @ -0,0 +1,196 @@ | |||
| /* | |||
| Copyright 2020-2023 Piotr Wilkon | |||
| This file is part of VP-Digi. | |||
| VP-Digi 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. | |||
| VP-Digi 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 VP-Digi. If not, see <http://www.gnu.org/licenses/>. | |||
| */ | |||
| /* | |||
| * This file is kind of HAL for modem | |||
| */ | |||
| #ifndef DRIVERS_MODEM_LL_H_ | |||
| #define DRIVERS_MODEM_LL_H_ | |||
| #include <stdint.h> | |||
| //Oversampling factor | |||
| //This is a helper value, not a setting that can be changed without further code modification! | |||
| #define MODEM_LL_OVERSAMPLING_FACTOR 4 | |||
| #if defined(STM32F103xB) || defined(STM32F103x8) | |||
| #include "stm32f1xx.h" | |||
| /** | |||
| * TIM1 is used for pushing samples to DAC (R2R or PWM) (clocked at 18 MHz) | |||
| * TIM3 is the baudrate generator for TX (clocked at 18 MHz) | |||
| * TIM4 is the PWM generator with no software interrupt | |||
| * TIM2 is the RX sampling timer with no software interrupt, but it directly calls DMA | |||
| */ | |||
| #define MODEM_LL_DMA_INTERRUPT_HANDLER DMA1_Channel2_IRQHandler | |||
| #define MODEM_LL_DAC_INTERRUPT_HANDLER TIM1_UP_IRQHandler | |||
| #define MODEM_LL_BAUDRATE_TIMER_INTERRUPT_HANDLER TIM3_IRQHandler | |||
| #define MODEM_LL_DMA_IRQ DMA1_Channel2_IRQn | |||
| #define MODEM_LL_DAC_IRQ TIM1_UP_IRQn | |||
| #define MODEM_LL_BAUDRATE_TIMER_IRQ TIM3_IRQn | |||
| #define MODEM_LL_DMA_TRANSFER_COMPLETE_FLAG (DMA1->ISR & DMA_ISR_TCIF2) | |||
| #define MODEM_LL_DMA_CLEAR_TRANSFER_COMPLETE_FLAG() {DMA1->IFCR |= DMA_IFCR_CTCIF2;} | |||
| #define MODEM_LL_BAUDRATE_TIMER_CLEAR_INTERRUPT_FLAG() {TIM3->SR &= ~TIM_SR_UIF;} | |||
| #define MODEM_LL_BAUDRATE_TIMER_ENABLE() {TIM3->CR1 = TIM_CR1_CEN;} | |||
| #define MODEM_LL_BAUDRATE_TIMER_DISABLE() {TIM3->CR1 &= ~TIM_CR1_CEN;} | |||
| #define MODEM_LL_BAUDRATE_TIMER_SET_RELOAD_VALUE(val) {TIM3->ARR = (val);} | |||
| #define MODEM_LL_DAC_TIMER_CLEAR_INTERRUPT_FLAG {TIM1->SR &= ~TIM_SR_UIF;} | |||
| #define MODEM_LL_DAC_TIMER_SET_RELOAD_VALUE(val) {TIM1->ARR = (val);} | |||
| #define MODEM_LL_DAC_TIMER_SET_CURRENT_VALUE(val) {TIM1->CNT = (val);} | |||
| #define MODEM_LL_DAC_TIMER_ENABLE() {TIM1->CR1 |= TIM_CR1_CEN;} | |||
| #define MODEM_LL_DAC_TIMER_DISABLE() {TIM1->CR1 &= ~TIM_CR1_CEN;} | |||
| #define MODEM_LL_ADC_TIMER_ENABLE() {TIM2->CR1 |= TIM_CR1_CEN;} | |||
| #define MODEM_LL_ADC_TIMER_DISABLE() {TIM2->CR1 &= ~TIM_CR1_CEN;} | |||
| #define MODEM_LL_PWM_PUT_VALUE(value) {TIM4->CCR1 = (value);} | |||
| #define MODEM_LL_R2R_PUT_VALUE(value) {GPIOB->ODR &= ~0xF000; \ | |||
| GPIOB->ODR |= ((uint32_t)(value) << 12); }\ | |||
| #define MODEM_LL_DCD_LED_ON() { \ | |||
| GPIOC->BSRR = GPIO_BSRR_BR13; \ | |||
| GPIOB->BSRR = GPIO_BSRR_BS5; \ | |||
| } \ | |||
| #define MODEM_LL_DCD_LED_OFF() { \ | |||
| GPIOC->BSRR = GPIO_BSRR_BS13; \ | |||
| GPIOB->BSRR = GPIO_BSRR_BR5; \ | |||
| } \ | |||
| #define MODEM_LL_PTT_ON() {GPIOB->BSRR = GPIO_BSRR_BS7;} | |||
| #define MODEM_LL_PTT_OFF() {GPIOB->BSRR = GPIO_BSRR_BR7;} | |||
| #define MODEM_LL_INITIALIZE_RCC() { \ | |||
| RCC->APB2ENR |= RCC_APB2ENR_IOPBEN; \ | |||
| RCC->APB2ENR |= RCC_APB2ENR_IOPCEN; \ | |||
| RCC->APB2ENR |= RCC_APB2ENR_IOPAEN; \ | |||
| RCC->APB1ENR |= RCC_APB1ENR_TIM2EN; \ | |||
| RCC->APB1ENR |= RCC_APB1ENR_TIM3EN; \ | |||
| RCC->APB2ENR |= RCC_APB2ENR_TIM1EN; \ | |||
| RCC->APB2ENR |= RCC_APB2ENR_ADC1EN; \ | |||
| RCC->AHBENR |= RCC_AHBENR_DMA1EN; \ | |||
| RCC->APB1ENR |= RCC_APB1ENR_TIM4EN; \ | |||
| } \ | |||
| #define MODEM_LL_INITIALIZE_OUTPUTS() { \ | |||
| /* DCD LEDs: PC13 (cathode driven - built-in LED on Blue Pill) and PB5 (anode driven) */ \ | |||
| GPIOC->CRH |= GPIO_CRH_MODE13_1; \ | |||
| GPIOC->CRH &= ~GPIO_CRH_MODE13_0; \ | |||
| GPIOC->CRH &= ~GPIO_CRH_CNF13; \ | |||
| GPIOB->CRL |= GPIO_CRL_MODE5_1; \ | |||
| GPIOB->CRL &= ~GPIO_CRL_MODE5_0; \ | |||
| GPIOB->CRL &= ~GPIO_CRL_CNF5; \ | |||
| /* PTT: PB7 */ \ | |||
| GPIOB->CRL |= GPIO_CRL_MODE7_1; \ | |||
| GPIOB->CRL &= ~GPIO_CRL_MODE7_0; \ | |||
| GPIOB->CRL &= ~GPIO_CRL_CNF7; \ | |||
| /* R2R: 4 bits, PB12-PB15 */ \ | |||
| GPIOB->CRH &= ~0xFFFF0000; \ | |||
| GPIOB->CRH |= 0x22220000; \ | |||
| /* PWM output: PB6 */ \ | |||
| GPIOB->CRL |= GPIO_CRL_CNF6_1; \ | |||
| GPIOB->CRL |= GPIO_CRL_MODE6; \ | |||
| GPIOB->CRL &= ~GPIO_CRL_CNF6_0; \ | |||
| } \ | |||
| #define MODEM_LL_INITIALIZE_ADC() { \ | |||
| /* ADC input: PA0 */ \ | |||
| GPIOA->CRL &= ~GPIO_CRL_CNF0; \ | |||
| GPIOA->CRL &= ~GPIO_CRL_MODE0; \ | |||
| /*/6 prescaler */ \ | |||
| RCC->CFGR |= RCC_CFGR_ADCPRE_1; \ | |||
| RCC->CFGR &= ~RCC_CFGR_ADCPRE_0; \ | |||
| ADC1->CR2 |= ADC_CR2_CONT; \ | |||
| ADC1->CR2 |= ADC_CR2_EXTSEL; \ | |||
| ADC1->SQR1 &= ~ADC_SQR1_L; \ | |||
| /* 41.5 cycle sampling */ \ | |||
| ADC1->SMPR2 |= ADC_SMPR2_SMP0_2; \ | |||
| ADC1->SQR3 &= ~ADC_SQR3_SQ1; \ | |||
| ADC1->CR2 |= ADC_CR2_ADON; \ | |||
| /* calibrate */ \ | |||
| ADC1->CR2 |= ADC_CR2_RSTCAL; \ | |||
| while(ADC1->CR2 & ADC_CR2_RSTCAL) \ | |||
| ; \ | |||
| ADC1->CR2 |= ADC_CR2_CAL; \ | |||
| while(ADC1->CR2 & ADC_CR2_CAL) \ | |||
| ; \ | |||
| ADC1->CR2 |= ADC_CR2_EXTTRIG; \ | |||
| ADC1->CR2 |= ADC_CR2_SWSTART; \ | |||
| } \ | |||
| #define MODEM_LL_INITIALIZE_DMA(buffer) { \ | |||
| /* 16 bit memory region */ \ | |||
| DMA1_Channel2->CCR |= DMA_CCR_MSIZE_0; \ | |||
| DMA1_Channel2->CCR &= ~DMA_CCR_MSIZE_1; \ | |||
| DMA1_Channel2->CCR |= DMA_CCR_PSIZE_0; \ | |||
| DMA1_Channel2->CCR &= ~DMA_CCR_PSIZE_1; \ | |||
| /* enable memory pointer increment, circular mode and interrupt generation */ \ | |||
| DMA1_Channel2->CCR |= DMA_CCR_MINC | DMA_CCR_CIRC| DMA_CCR_TCIE; \ | |||
| DMA1_Channel2->CNDTR = MODEM_LL_OVERSAMPLING_FACTOR; \ | |||
| DMA1_Channel2->CPAR = (uintptr_t)&(ADC1->DR); \ | |||
| DMA1_Channel2->CMAR = (uintptr_t)buffer; \ | |||
| DMA1_Channel2->CCR |= DMA_CCR_EN; \ | |||
| } \ | |||
| #define MODEM_LL_ADC_TIMER_INITIALIZE() { \ | |||
| /* 72 / 9 = 8 MHz */ \ | |||
| TIM2->PSC = 8; \ | |||
| /* enable DMA call instead of standard interrupt */ \ | |||
| TIM2->DIER |= TIM_DIER_UDE; \ | |||
| } \ | |||
| #define MODEM_LL_DAC_TIMER_INITIALIZE() { \ | |||
| /* 72 / 4 = 18 MHz */ \ | |||
| TIM1->PSC = 3; \ | |||
| TIM1->DIER |= TIM_DIER_UIE; \ | |||
| } \ | |||
| #define MODEM_LL_BAUDRATE_TIMER_INITIALIZE() { \ | |||
| /* 72 / 4 = 18 MHz */ \ | |||
| TIM3->PSC = 3; \ | |||
| TIM3->DIER |= TIM_DIER_UIE; \ | |||
| } \ | |||
| #define MODEM_LL_PWM_INITIALIZE() { \ | |||
| /* 72 / 3 = 24 MHz to provide 8 bit resolution at around 100 kHz */ \ | |||
| TIM4->PSC = 2; \ | |||
| /* 24 MHz / 258 = 93 kHz */ \ | |||
| TIM4->ARR = 257; \ | |||
| TIM4->CCMR1 |= TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_2; \ | |||
| TIM4->CCER |= TIM_CCER_CC1E; \ | |||
| TIM4->CR1 |= TIM_CR1_CEN; \ | |||
| } \ | |||
| #define MODEM_LL_ADC_SET_SAMPLE_RATE(rate) {TIM2->ARR = (8000000 / (rate)) - 1;} | |||
| #define MODEM_LL_DAC_TIMER_CALCULATE_STEP(frequency) ((18000000 / (frequency)) - 1) | |||
| #define MODEM_LL_BAUDRATE_TIMER_CALCULATE_STEP(frequency) ((18000000 / (frequency)) - 1) | |||
| #endif | |||
| #endif /* DRIVERS_MODEM_LL_H_ */ | |||
| @ -0,0 +1,81 @@ | |||
| /* | |||
| Copyright 2020-2023 Piotr Wilkon | |||
| This file is part of VP-Digi. | |||
| VP-Digi 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. | |||
| VP-Digi 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 VP-Digi. If not, see <http://www.gnu.org/licenses/>. | |||
| */ | |||
| /* | |||
| * This file is kind of HAL for UART | |||
| */ | |||
| #ifndef DRIVERS_UART_LL_H_ | |||
| #define DRIVERS_UART_LL_H_ | |||
| #if defined(STM32F103xB) || defined(STM32F103x8) | |||
| #include "stm32f1xx.h" | |||
| #define UART_LL_ENABLE(port) {port->CR1 |= USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE | USART_CR1_UE | USART_CR1_IDLEIE;} | |||
| #define UART_LL_DISABLE(port) {port->CR1 &= (~USART_CR1_RXNEIE) & (~USART_CR1_TE) & (~USART_CR1_RE) & (~USART_CR1_UE) & (~USART_CR1_IDLEIE);} | |||
| #define UART_LL_CHECK_RX_NOT_EMPTY(port) (port->SR & USART_SR_RXNE) | |||
| #define UART_LL_CLEAR_RX_NOT_EMPTY(port) {port->SR &= ~USART_SR_RXNE;} | |||
| #define UART_LL_CHECK_TX_EMPTY(port) (port->SR & USART_SR_TXE) | |||
| #define UART_LL_ENABLE_TX_EMPTY_INTERRUPT(port) {port->CR1 |= USART_CR1_TXEIE;} | |||
| #define UART_LL_DISABLE_TX_EMPTY_INTERRUPT(port) {port->CR1 &= ~USART_CR1_TXEIE;} | |||
| #define UART_LL_CHECK_ENABLED_TX_EMPTY_INTERRUPT(port) (port->CR1 & USART_CR1_TXEIE) | |||
| #define UART_LL_CHECK_RX_IDLE(port) (port->SR & USART_SR_IDLE) | |||
| #define UART_LL_GET_DATA(port) (port->DR) | |||
| #define UART_LL_PUT_DATA(port, data) {port->DR = (data);} | |||
| #define UART_LL_UART1_INTERUPT_HANDLER USART1_IRQHandler | |||
| #define UART_LL_UART2_INTERUPT_HANDLER USART2_IRQHandler | |||
| #define UART_LL_UART1_STRUCTURE USART1 | |||
| #define UART_LL_UART2_STRUCTURE USART2 | |||
| #define UART_LL_UART1_IRQ USART1_IRQn | |||
| #define UART_LL_UART2_IRQ USART2_IRQn | |||
| #define UART_LL_UART1_INITIALIZE_PERIPHERAL(baudrate) { \ | |||
| RCC->APB2ENR |= RCC_APB2ENR_IOPAEN; \ | |||
| RCC->APB2ENR |= RCC_APB2ENR_USART1EN; \ | |||
| GPIOA->CRH |= GPIO_CRH_MODE9_1; \ | |||
| GPIOA->CRH &= ~GPIO_CRH_CNF9_0; \ | |||
| GPIOA->CRH |= GPIO_CRH_CNF9_1; \ | |||
| GPIOA->CRH |= GPIO_CRH_CNF10_0; \ | |||
| GPIOA->CRH &= ~GPIO_CRH_CNF10_1; \ | |||
| UART_LL_UART1_STRUCTURE->BRR = (SystemCoreClock / baudrate); \ | |||
| } \ | |||
| #define UART_LL_UART2_INITIALIZE_PERIPHERAL(baudrate) { \ | |||
| RCC->APB2ENR |= RCC_APB2ENR_IOPAEN; \ | |||
| RCC->APB1ENR |= RCC_APB1ENR_USART2EN; \ | |||
| GPIOA->CRL |= GPIO_CRL_MODE2_1; \ | |||
| GPIOA->CRL &= ~GPIO_CRL_CNF2_0; \ | |||
| GPIOA->CRL |= GPIO_CRL_CNF2_1; \ | |||
| GPIOA->CRL |= GPIO_CRL_CNF3_0; \ | |||
| GPIOA->CRL &= ~GPIO_CRL_CNF3_1; \ | |||
| UART_LL_UART2_STRUCTURE->BRR = (SystemCoreClock / (baudrate * 2)); \ | |||
| } \ | |||
| #endif | |||
| #endif /* INC_DRIVERS_UART_LL_H_ */ | |||
| @ -0,0 +1,76 @@ | |||
| /* | |||
| Copyright 2020-2023 Piotr Wilkon | |||
| This file is part of VP-Digi. | |||
| VP-Digi 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. | |||
| VP-Digi 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 VP-Digi. If not, see <http://www.gnu.org/licenses/>. | |||
| */ | |||
| #ifndef FX25_H_ | |||
| #define FX25_H_ | |||
| #ifdef ENABLE_FX25 | |||
| #include <stdint.h> | |||
| #include <stdbool.h> | |||
| #define FX25_MAX_BLOCK_SIZE 255 | |||
| struct Fx25Mode | |||
| { | |||
| uint64_t tag; //correlation tag | |||
| uint16_t K; //data size | |||
| uint8_t T; //parity check size | |||
| }; | |||
| extern const struct Fx25Mode Fx25ModeList[11]; | |||
| /** | |||
| * @brief Get FX.25 mode for given correlation tag | |||
| * @param tag FX.25 correlation tag | |||
| * @return FX.25 mode structure pointer or NULL if not a FX.25 tag | |||
| */ | |||
| const struct Fx25Mode* Fx25GetModeForTag(uint64_t tag); | |||
| /** | |||
| * @brief Get FX.25 mode for given payload size | |||
| * @param size Payload size including flags and CRC | |||
| * @return FX.25 mode structure pointer or NULL if standard AX.25 must be used | |||
| */ | |||
| const struct Fx25Mode* Fx25GetModeForSize(uint16_t size); | |||
| /** | |||
| * @brief Encode AX.25 message in FX.25 | |||
| * @param *buffer AX.25 message (bit-stuffed, with CRC and padding) | |||
| * @param *mode FX.25 mode | |||
| */ | |||
| void Fx25Encode(uint8_t *buffer, const struct Fx25Mode *mode); | |||
| /** | |||
| * @brief Decode/fix FX.25 packet | |||
| * @param *buffer Input buffer | |||
| * @param *mode FX.25 mode | |||
| * @param *fixed Number of bytes fixed | |||
| * @return True if message is valid, false if uncorrectable | |||
| */ | |||
| bool Fx25Decode(uint8_t *buffer, const struct Fx25Mode *mode, uint8_t *fixed); | |||
| /** | |||
| * @brief Initialize FX.25 module | |||
| */ | |||
| void Fx25Init(void); | |||
| #endif | |||
| #endif /* FX25_H_ */ | |||
| @ -0,0 +1,974 @@ | |||
| /* | |||
| Copyright 2020-2023 Piotr Wilkon | |||
| This file is part of VP-Digi. | |||
| VP-Digi 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. | |||
| VP-Digi 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 VP-Digi. If not, see <http://www.gnu.org/licenses/>. | |||
| */ | |||
| #include "modem.h" | |||
| #include "ax25.h" | |||
| #include <stdlib.h> | |||
| #include "common.h" | |||
| #include <stdbool.h> | |||
| #include <string.h> | |||
| #include "systick.h" | |||
| #include "digipeater.h" | |||
| struct Ax25ProtoConfig Ax25Config; | |||
| #ifdef ENABLE_FX25 | |||
| #include "fx25.h" | |||
| #endif | |||
| #define FRAME_MAX_COUNT (10) //max count of frames in buffer | |||
| #define FRAME_BUFFER_SIZE (FRAME_MAX_COUNT * AX25_FRAME_MAX_SIZE) //circular frame buffer length | |||
| #define STATIC_HEADER_FLAG_COUNT 4 //number of flags sent before each frame | |||
| #define STATIC_FOOTER_FLAG_COUNT 8 //number of flags sent after each frame | |||
| #define MAX_TRANSMIT_RETRY_COUNT 8 //max number of retries if channel is busy | |||
| #define SYNC_BYTE 0x7E //preamble/postamble octet | |||
| struct FrameHandle | |||
| { | |||
| uint16_t start; | |||
| uint16_t size; | |||
| int8_t peak; | |||
| int8_t valley; | |||
| uint8_t level; | |||
| uint8_t corrected; | |||
| #ifdef ENABLE_FX25 | |||
| struct Fx25Mode *fx25Mode; | |||
| #endif | |||
| }; | |||
| static uint8_t rxBuffer[FRAME_BUFFER_SIZE]; //circular buffer for received frames | |||
| static uint16_t rxBufferHead = 0; //circular RX buffer write index | |||
| static struct FrameHandle rxFrame[FRAME_MAX_COUNT]; | |||
| static uint8_t rxFrameHead = 0; | |||
| static uint8_t rxFrameTail = 0; | |||
| static bool rxFrameBufferFull = false; | |||
| static uint8_t txBuffer[FRAME_BUFFER_SIZE]; //circular TX frame buffer | |||
| static uint16_t txBufferHead = 0; //circular TX buffer write index | |||
| static uint16_t txBufferTail = 0; | |||
| static struct FrameHandle txFrame[FRAME_MAX_COUNT]; | |||
| static uint8_t txFrameHead = 0; | |||
| static uint8_t txFrameTail = 0; | |||
| static bool txFrameBufferFull = false; | |||
| #ifdef ENABLE_FX25 | |||
| static uint8_t txFx25Buffer[FX25_MAX_BLOCK_SIZE]; | |||
| static uint8_t txTagByteIdx = 0; | |||
| #endif | |||
| static uint8_t frameReceived; //a bitmap of receivers that received the frame | |||
| enum TxStage | |||
| { | |||
| TX_STAGE_IDLE = 0, | |||
| TX_STAGE_PREAMBLE, | |||
| TX_STAGE_HEADER_FLAGS, | |||
| TX_STAGE_DATA, | |||
| TX_STAGE_CRC, | |||
| TX_STAGE_FOOTER_FLAGS, | |||
| TX_STAGE_TAIL, | |||
| #ifdef ENABLE_FX25 | |||
| //stages used in FX.25 mode additionally | |||
| TX_STAGE_CORRELATION_TAG, | |||
| #endif | |||
| }; | |||
| enum TxInitStage | |||
| { | |||
| TX_INIT_OFF, | |||
| TX_INIT_WAITING, | |||
| TX_INIT_TRANSMITTING | |||
| }; | |||
| static uint8_t txByte = 0; //current TX byte | |||
| static uint16_t txByteIdx = 0; //current TX byte index | |||
| static int8_t txBitIdx = 0; //current bit index in txByte | |||
| static uint16_t txDelayElapsed = 0; //counter of TXDelay bytes already sent | |||
| static uint8_t txFlagsElapsed = 0; //counter of flag bytes already sent | |||
| static uint8_t txCrcByteIdx = 0; //currently transmitted byte of CRC | |||
| static uint8_t txBitstuff = 0; //bit-stuffing counter | |||
| static uint16_t txTailElapsed; //counter of TXTail bytes already sent | |||
| static uint16_t txCrc = 0xFFFF; //current CRC | |||
| static uint32_t txQuiet = 0; //quit time + current tick value | |||
| static uint8_t txRetries = 0; //number of TX retries | |||
| static enum TxInitStage txInitStage; //current TX initialization stage | |||
| static enum TxStage txStage; //current TX stage | |||
| struct RxState | |||
| { | |||
| uint16_t crc; //current CRC | |||
| uint8_t frame[AX25_FRAME_MAX_SIZE]; //raw frame buffer | |||
| uint16_t frameIdx; //index for raw frame buffer | |||
| uint8_t receivedByte; //byte being currently received | |||
| uint8_t receivedBitIdx; //bit index for recByte | |||
| uint8_t rawData; //raw data being currently received | |||
| enum Ax25RxStage rx; //current RX stage | |||
| uint8_t frameReceived; //frame received flag | |||
| #ifdef ENABLE_FX25 | |||
| struct Fx25Mode *fx25Mode; | |||
| uint64_t tag; //received correlation tag | |||
| #endif | |||
| }; | |||
| static struct RxState rxState[MODEM_MAX_DEMODULATOR_COUNT]; | |||
| static uint16_t lastCrc = 0; //CRC of the last received frame. If not 0, a frame was successfully received | |||
| static uint16_t rxMultiplexDelay = 0; //simple delay for decoder multiplexer to avoid receiving the same frame twice | |||
| static uint16_t txDelay; //number of TXDelay bytes to send | |||
| static uint16_t txTail; //number of TXTail bytes to send | |||
| static uint8_t outputFrameBuffer[AX25_FRAME_MAX_SIZE]; | |||
| #define GET_FREE_SIZE(max, head, tail) (((head) < (tail)) ? ((tail) - (head)) : ((max) - (head) + (tail))) | |||
| #define GET_USED_SIZE(max, head, tail) (max - GET_FREE_SIZE(max, head, tail)) | |||
| /** | |||
| * @brief Recalculate CRC for one bit | |||
| * @param bit Input bit | |||
| * @param *crc CRC pointer | |||
| */ | |||
| static void calculateCRC(uint8_t bit, uint16_t *crc) | |||
| { | |||
| uint16_t xor_result; | |||
| xor_result = *crc ^ bit; | |||
| *crc >>= 1; | |||
| if (xor_result & 0x0001) | |||
| { | |||
| *crc ^= 0x8408; | |||
| } | |||
| } | |||
| uint8_t Ax25GetReceivedFrameBitmap(void) | |||
| { | |||
| return frameReceived; | |||
| } | |||
| void Ax25ClearReceivedFrameBitmap(void) | |||
| { | |||
| frameReceived = 0; | |||
| } | |||
| #ifdef ENABLE_FX25 | |||
| static void removeLastFrameFromRxBuffer(void) | |||
| { | |||
| rxBufferHead = rxFrame[rxFrameHead].start; | |||
| if(rxFrameHead == 0) | |||
| rxFrameHead = FRAME_MAX_COUNT - 1; | |||
| else | |||
| rxFrameHead--; | |||
| rxFrameBufferFull = false; | |||
| } | |||
| static void *writeFx25Frame(uint8_t *data, uint16_t size) | |||
| { | |||
| //first calculate how big the frame can be | |||
| //this includes 2 flags, 2 CRC bytes and all bits added by bitstuffing | |||
| //bitstuffing occurs after 5 consecutive ones, so in worst scenario | |||
| //bits inserted by bitstuffing can occupy up to frame size / 5 additional bytes | |||
| //also add 1 in case there is a remainder when dividing | |||
| const struct Fx25Mode *fx25Mode = fx25Mode = Fx25GetModeForSize(size + 4 + (size / 5) + 1); | |||
| uint16_t requiredSize = size; | |||
| if(NULL != fx25Mode) | |||
| requiredSize = fx25Mode->K + fx25Mode->T; | |||
| else | |||
| return NULL; //frame will not fit in FX.25 | |||
| uint16_t freeSize = GET_FREE_SIZE(FRAME_BUFFER_SIZE, txBufferHead, txBufferTail); | |||
| if(freeSize < requiredSize) //check if there is enough size to store full FX.25 (or AX.25) frame | |||
| { | |||
| return NULL; //if not, it may fit in standard AX.25 | |||
| } | |||
| txFrame[txFrameHead].size = requiredSize; | |||
| txFrame[txFrameHead].start = txBufferHead; | |||
| txFrame[txFrameHead].fx25Mode = (struct Fx25Mode*)fx25Mode; | |||
| memset(txFx25Buffer, 0, sizeof(txFx25Buffer)); | |||
| uint16_t index = 0; | |||
| //header flag | |||
| txFx25Buffer[index++] = 0x7E; | |||
| uint16_t crc = 0xFFFF; | |||
| uint8_t bits = 0; //bit counter within a byte | |||
| uint8_t bitstuff = 0; | |||
| for(uint16_t i = 0; i < size + 2; i++) | |||
| { | |||
| for(uint8_t k = 0; k < 8; k++) | |||
| { | |||
| txFx25Buffer[index] >>= 1; | |||
| bits++; | |||
| if(i < size) //frame data | |||
| { | |||
| if((data[i] >> k) & 1) | |||
| { | |||
| calculateCRC(1, &crc); | |||
| bitstuff++; | |||
| txFx25Buffer[index] |= 0x80; | |||
| } | |||
| else | |||
| { | |||
| calculateCRC(0, &crc); | |||
| bitstuff = 0; | |||
| } | |||
| } | |||
| else //crc | |||
| { | |||
| uint8_t c = 0; | |||
| if(i == size) | |||
| c = (crc & 0xFF) ^ 0xFF; | |||
| else | |||
| c = (crc >> 8) ^ 0xFF; | |||
| if((c >> k) & 1) | |||
| { | |||
| bitstuff++; | |||
| txFx25Buffer[index] |= 0x80; | |||
| } | |||
| else | |||
| { | |||
| bitstuff = 0; | |||
| } | |||
| } | |||
| if(bits == 8) | |||
| { | |||
| bits = 0; | |||
| index++; | |||
| } | |||
| if(bitstuff == 5) | |||
| { | |||
| bits++; | |||
| bitstuff = 0; | |||
| txFx25Buffer[index] >>= 1; | |||
| if(bits == 8) | |||
| { | |||
| bits = 0; | |||
| index++; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| //pad with flags | |||
| while(index < fx25Mode->K) | |||
| { | |||
| for(uint8_t k = 0; k < 8; k++) | |||
| { | |||
| txFx25Buffer[index] >>= 1; | |||
| bits++; | |||
| if((0x7E >> k) & 1) | |||
| { | |||
| txFx25Buffer[index] |= 0x80; | |||
| } | |||
| if(bits == 8) | |||
| { | |||
| bits = 0; | |||
| index++; | |||
| } | |||
| } | |||
| } | |||
| Fx25Encode(txFx25Buffer, fx25Mode); | |||
| for(uint16_t i = 0; i < (fx25Mode->K + fx25Mode->T); i++) | |||
| { | |||
| txBuffer[txBufferHead++] = txFx25Buffer[i]; | |||
| txBufferHead %= FRAME_BUFFER_SIZE; | |||
| } | |||
| void *ret = &txFrame[txFrameHead]; | |||
| txFrameHead++; | |||
| txFrameHead %= FRAME_MAX_COUNT; | |||
| if(txFrameHead == txFrameTail) | |||
| txFrameBufferFull = true; | |||
| return ret; | |||
| } | |||
| static struct FrameHandle* parseFx25Frame(uint8_t *frame, uint16_t size, uint16_t *crc) | |||
| { | |||
| struct FrameHandle *h = &rxFrame[rxFrameHead]; | |||
| uint16_t initialRxBufferHead = rxBufferHead; | |||
| if(!rxFrameBufferFull) | |||
| { | |||
| rxFrame[rxFrameHead++].start = rxBufferHead; | |||
| rxFrameHead %= FRAME_MAX_COUNT; | |||
| if(rxFrameHead == txFrameHead) | |||
| rxFrameBufferFull = true; | |||
| } | |||
| else | |||
| return NULL; | |||
| uint16_t i = 0; //input data index | |||
| uint16_t k = 0; //output data size | |||
| while(frame[i] == 0x7E) | |||
| i++; | |||
| uint8_t bitstuff = 0; | |||
| uint8_t outBit = 0; | |||
| for(; i < size; i++) | |||
| { | |||
| for(uint8_t b = 0; b < 8; b++) | |||
| { | |||
| if(frame[i] & (1 << b)) | |||
| { | |||
| rxBuffer[rxBufferHead] >>= 1; | |||
| rxBuffer[rxBufferHead] |= 0x80; | |||
| bitstuff++; | |||
| } | |||
| else | |||
| { | |||
| if(bitstuff == 5) //zero after 5 ones, normal bitstuffing | |||
| { | |||
| bitstuff = 0; | |||
| continue; | |||
| } | |||
| else if(bitstuff == 6) //zero after 6 ones, this is a flag | |||
| { | |||
| goto endParseFx25Frame; | |||
| } | |||
| else if(bitstuff >= 7) //zero after 7 ones, illegal byte | |||
| { | |||
| removeLastFrameFromRxBuffer(); | |||
| return NULL; | |||
| } | |||
| bitstuff = 0; | |||
| rxBuffer[rxBufferHead] >>= 1; | |||
| } | |||
| outBit++; | |||
| if(outBit == 8) | |||
| { | |||
| k++; | |||
| rxBufferHead++; | |||
| rxBufferHead %= FRAME_BUFFER_SIZE; | |||
| outBit = 0; | |||
| } | |||
| } | |||
| } | |||
| endParseFx25Frame: | |||
| *crc = 0xFFFF; | |||
| i = initialRxBufferHead; | |||
| for(uint16_t j = 0; j < (k - 2); j++) | |||
| { | |||
| for(uint8_t b = 0; b < 8; b++) | |||
| calculateCRC((rxBuffer[i] >> b) & 1, crc); | |||
| i++; | |||
| i %= FRAME_BUFFER_SIZE; | |||
| } | |||
| *crc ^= 0xFFFF; | |||
| if((rxBuffer[i] == (*crc & 0xFF) ) | |||
| && (rxBuffer[(i + 1) % FRAME_BUFFER_SIZE] == ((*crc >> 8) & 0xFF))) //check CRC | |||
| { | |||
| uint16_t pathEnd = initialRxBufferHead; | |||
| for(uint16_t j = 0; j < (k - 2); j++) | |||
| { | |||
| if(rxBuffer[pathEnd] & 1) | |||
| break; | |||
| pathEnd++; | |||
| pathEnd %= FRAME_BUFFER_SIZE; | |||
| } | |||
| if(Ax25Config.allowNonAprs || (((rxBuffer[(pathEnd + 1) % FRAME_BUFFER_SIZE] == 0x03) && (rxBuffer[(pathEnd + 2) % FRAME_BUFFER_SIZE] == 0xF0)))) | |||
| { | |||
| h->size = k - 2; | |||
| return h; | |||
| } | |||
| } | |||
| removeLastFrameFromRxBuffer(); | |||
| return NULL; | |||
| } | |||
| #endif | |||
| void *Ax25WriteTxFrame(uint8_t *data, uint16_t size) | |||
| { | |||
| if(txFrameBufferFull) | |||
| return NULL; | |||
| #ifdef ENABLE_FX25 | |||
| if(Ax25Config.fx25 && Ax25Config.fx25Tx) | |||
| { | |||
| void *ret = writeFx25Frame(data, size); | |||
| if(ret) | |||
| return ret; | |||
| } | |||
| #endif | |||
| if(GET_FREE_SIZE(FRAME_BUFFER_SIZE, txBufferHead, txBufferTail) < size) | |||
| { | |||
| return NULL; | |||
| } | |||
| txFrame[txFrameHead].size = size; | |||
| txFrame[txFrameHead].start = txBufferHead; | |||
| #ifdef ENABLE_FX25 | |||
| txFrame[txFrameHead].fx25Mode = NULL; | |||
| #endif | |||
| for(uint16_t i = 0; i < size; i++) | |||
| { | |||
| txBuffer[txBufferHead++] = data[i]; | |||
| txBufferHead %= FRAME_BUFFER_SIZE; | |||
| } | |||
| void *ret = &txFrame[txFrameHead]; | |||
| __disable_irq(); | |||
| txFrameHead++; | |||
| txFrameHead %= FRAME_MAX_COUNT; | |||
| if(txFrameHead == txFrameTail) | |||
| txFrameBufferFull = true; | |||
| __enable_irq(); | |||
| return ret; | |||
| } | |||
| bool Ax25ReadNextRxFrame(uint8_t **dst, uint16_t *size, int8_t *peak, int8_t *valley, uint8_t *level, uint8_t *corrected) | |||
| { | |||
| if((rxFrameHead == rxFrameTail) && !rxFrameBufferFull) | |||
| return false; | |||
| *dst = outputFrameBuffer; | |||
| for(uint16_t i = 0; i < rxFrame[rxFrameTail].size; i++) | |||
| { | |||
| (*dst)[i] = rxBuffer[(rxFrame[rxFrameTail].start + i) % FRAME_BUFFER_SIZE]; | |||
| } | |||
| *peak = rxFrame[rxFrameTail].peak; | |||
| *valley = rxFrame[rxFrameTail].valley; | |||
| *level = rxFrame[rxFrameTail].level; | |||
| *size = rxFrame[rxFrameTail].size; | |||
| *corrected = rxFrame[rxFrameTail].corrected; | |||
| __disable_irq(); | |||
| rxFrameBufferFull = false; | |||
| rxFrameTail++; | |||
| rxFrameTail %= FRAME_MAX_COUNT; | |||
| __enable_irq(); | |||
| return true; | |||
| } | |||
| enum Ax25RxStage Ax25GetRxStage(uint8_t modem) | |||
| { | |||
| return rxState[modem].rx; | |||
| } | |||
| void Ax25BitParse(uint8_t bit, uint8_t modem) | |||
| { | |||
| if(lastCrc != 0) //there was a frame received | |||
| { | |||
| rxMultiplexDelay++; | |||
| if(rxMultiplexDelay > (4 * MODEM_MAX_DEMODULATOR_COUNT)) //hold it for a while and wait for other decoders to receive the frame | |||
| { | |||
| lastCrc = 0; | |||
| rxMultiplexDelay = 0; | |||
| for(uint8_t i = 0; i < MODEM_MAX_DEMODULATOR_COUNT; i++) | |||
| { | |||
| frameReceived |= ((rxState[i].frameReceived > 0) << i); | |||
| rxState[i].frameReceived = 0; | |||
| } | |||
| } | |||
| } | |||
| struct RxState *rx = (struct RxState*)&(rxState[modem]); | |||
| rx->rawData <<= 1; //store incoming bit | |||
| rx->rawData |= (bit > 0); | |||
| #ifdef ENABLE_FX25 | |||
| rx->tag >>= 1; | |||
| if(bit) | |||
| rx->tag |= 0x8000000000000000; | |||
| if(Ax25Config.fx25 | |||
| && (rx->rx != RX_STAGE_FX25_FRAME) | |||
| && (NULL != (rx->fx25Mode = (struct Fx25Mode*)Fx25GetModeForTag(rx->tag)))) | |||
| { | |||
| rx->rx = RX_STAGE_FX25_FRAME; | |||
| rx->receivedByte = 0; | |||
| rx->receivedBitIdx = 0; | |||
| rx->frameIdx = 0; | |||
| return; | |||
| } | |||
| if(rx->rx != RX_STAGE_FX25_FRAME) | |||
| { | |||
| #endif | |||
| if(rx->rawData == 0x7E) //HDLC flag received | |||
| { | |||
| if(rx->rx == RX_STAGE_FRAME) //if we are in frame, this is the end of the frame | |||
| { | |||
| if(rx->frameIdx >= 17) //correct frame must be at least 17 bytes long (source+destination+control+CRC) | |||
| { | |||
| rx->crc ^= 0xFFFF; | |||
| if((rx->frame[rx->frameIdx - 2] == (rx->crc & 0xFF)) && (rx->frame[rx->frameIdx - 1] == ((rx->crc >> 8) & 0xFF))) //check CRC | |||
| { | |||
| uint16_t i = 13; | |||
| //start from 13, which is the SSID of source | |||
| for(; i < (rx->frameIdx - 2); i++) //look for path end bit | |||
| { | |||
| if(rx->frame[i] & 1) | |||
| break; | |||
| } | |||
| //if non-APRS frames are not allowed, check if this frame has control=0x03 and PID=0xF0 | |||
| if(Ax25Config.allowNonAprs || (((rx->frame[i + 1] == 0x03) && (rx->frame[i + 2] == 0xF0)))) | |||
| { | |||
| rx->frameReceived = 1; | |||
| rx->frameIdx -= 2; //remove CRC | |||
| if(rx->crc != lastCrc) //the other decoder has not received this frame yet, so store it in main frame buffer | |||
| { | |||
| lastCrc = rx->crc; //store CRC of this frame | |||
| if(!rxFrameBufferFull) //if enough space, store the frame | |||
| { | |||
| rxFrame[rxFrameHead].start = rxBufferHead; | |||
| ModemGetSignalLevel(modem, &rxFrame[rxFrameHead].peak, &rxFrame[rxFrameHead].valley, &rxFrame[rxFrameHead].level); | |||
| #ifdef ENABLE_FX25 | |||
| rxFrame[rxFrameHead].fx25Mode = NULL; | |||
| #endif | |||
| rxFrame[rxFrameHead].corrected = AX25_NOT_FX25; | |||
| __disable_irq(); | |||
| rxFrame[rxFrameHead++].size = rx->frameIdx; | |||
| rxFrameHead %= FRAME_MAX_COUNT; | |||
| if(rxFrameHead == rxFrameTail) | |||
| rxFrameBufferFull = true; | |||
| __enable_irq(); | |||
| for(uint16_t i = 0; i < rx->frameIdx; i++) | |||
| { | |||
| rxBuffer[rxBufferHead++] = rx->frame[i]; | |||
| rxBufferHead %= FRAME_BUFFER_SIZE; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| rx->rx = RX_STAGE_FLAG; | |||
| rx->receivedByte = 0; | |||
| rx->receivedBitIdx = 0; | |||
| rx->frameIdx = 0; | |||
| rx->crc = 0xFFFF; | |||
| return; | |||
| } | |||
| else | |||
| rx->rx = RX_STAGE_FRAME; | |||
| #ifndef ENABLE_FX25 | |||
| { | |||
| //this condition must not be checked when FX.25 is enabled | |||
| //because FX.25 parity bytes and tags contain >= 7 consecutive ones | |||
| if((rx->rawData & 0x7F) == 0x7F) //received 7 consecutive ones, this is an error | |||
| { | |||
| rx->rx = RX_STAGE_IDLE; | |||
| rx->receivedByte = 0; | |||
| rx->receivedBitIdx = 0; | |||
| rx->frameIdx = 0; | |||
| rx->crc = 0xFFFF; | |||
| return; | |||
| } | |||
| #endif | |||
| if((rx->rawData & 0x3F) == 0x3E) //dismiss bit 0 added by bit stuffing | |||
| return; | |||
| } | |||
| if(rx->rawData & 0x01) //received bit 1 | |||
| rx->receivedByte |= 0x80; //store it | |||
| if(++rx->receivedBitIdx >= 8) //received full byte | |||
| { | |||
| if(rx->frameIdx >= 2) | |||
| { | |||
| for(uint8_t k = 0; k < 8; k++) | |||
| { | |||
| calculateCRC((rx->frame[rx->frameIdx - 2] >> k) & 1, &(rx->crc)); | |||
| } | |||
| } | |||
| #ifdef ENABLE_FX25 | |||
| //end of FX.25 reception, that is received full block | |||
| if((rx->fx25Mode != NULL) && (rx->frameIdx == (rx->fx25Mode->K + rx->fx25Mode->T))) | |||
| { | |||
| uint8_t fixed = 0; | |||
| bool fecSuccess = Fx25Decode(rx->frame, rx->fx25Mode, &fixed); | |||
| uint16_t crc; | |||
| struct FrameHandle *h = parseFx25Frame(rx->frame, rx->frameIdx, &crc); | |||
| if(h != NULL) | |||
| { | |||
| rx->frameReceived = 1; | |||
| ModemGetSignalLevel(modem, &h->peak, &h->valley, &h->level); | |||
| if(fecSuccess) | |||
| { | |||
| h->corrected = fixed; | |||
| h->fx25Mode = rx->fx25Mode; | |||
| } | |||
| else | |||
| h->corrected = AX25_NOT_FX25; | |||
| lastCrc = crc; | |||
| } | |||
| rx->rx = RX_STAGE_FLAG; | |||
| rx->receivedByte = 0; | |||
| rx->receivedBitIdx = 0; | |||
| rx->frameIdx = 0; | |||
| return; | |||
| } | |||
| #else | |||
| rx->rx = RX_STAGE_FRAME; | |||
| #endif | |||
| if(rx->frameIdx >= AX25_FRAME_MAX_SIZE) //frame is too long | |||
| { | |||
| rx->rx = RX_STAGE_IDLE; | |||
| rx->receivedByte = 0; | |||
| rx->receivedBitIdx = 0; | |||
| rx->frameIdx = 0; | |||
| rx->crc = 0xFFFF; | |||
| return; | |||
| } | |||
| rx->frame[rx->frameIdx++] = rx->receivedByte; //store received byte | |||
| rx->receivedByte = 0; | |||
| rx->receivedBitIdx = 0; | |||
| } | |||
| else | |||
| rx->receivedByte >>= 1; | |||
| } | |||
| uint8_t Ax25GetTxBit(void) | |||
| { | |||
| if(txBitIdx == 8) | |||
| { | |||
| txBitIdx = 0; | |||
| if(txStage == TX_STAGE_PREAMBLE) //transmitting preamble (TXDelay) | |||
| { | |||
| if(txDelayElapsed < txDelay) | |||
| { | |||
| txByte = SYNC_BYTE; | |||
| txDelayElapsed++; | |||
| } | |||
| else | |||
| { | |||
| txDelayElapsed = 0; | |||
| #ifdef ENABLE_FX25 | |||
| if(NULL != txFrame[txFrameTail].fx25Mode) | |||
| { | |||
| txStage = TX_STAGE_CORRELATION_TAG; | |||
| txTagByteIdx = 0; | |||
| } | |||
| else | |||
| #endif | |||
| txStage = TX_STAGE_HEADER_FLAGS; | |||
| } | |||
| } | |||
| #ifdef ENABLE_FX25 | |||
| transmitTag: | |||
| if(txStage == TX_STAGE_CORRELATION_TAG) //FX.25 correlation tag | |||
| { | |||
| if(txTagByteIdx < 8) | |||
| txByte = (txFrame[txFrameTail].fx25Mode->tag >> (8 * txTagByteIdx)) & 0xFF; | |||
| else | |||
| txStage = TX_STAGE_DATA; | |||
| txTagByteIdx++; | |||
| } | |||
| #endif | |||
| if(txStage == TX_STAGE_HEADER_FLAGS) //transmitting initial flags | |||
| { | |||
| if(txFlagsElapsed < STATIC_HEADER_FLAG_COUNT) | |||
| { | |||
| txByte = 0x7E; | |||
| txFlagsElapsed++; | |||
| } | |||
| else | |||
| { | |||
| txFlagsElapsed = 0; | |||
| txStage = TX_STAGE_DATA; //transmit data | |||
| } | |||
| } | |||
| if(txStage == TX_STAGE_DATA) //transmitting normal data | |||
| { | |||
| transmitNormalData: | |||
| __disable_irq(); | |||
| if((txFrameHead != txFrameTail) || txFrameBufferFull) | |||
| { | |||
| __enable_irq(); | |||
| if(txByteIdx < txFrame[txFrameTail].size) //send buffer | |||
| { | |||
| txByte = txBuffer[(txFrame[txFrameTail].start + txByteIdx) % FRAME_BUFFER_SIZE]; | |||
| txByteIdx++; | |||
| } | |||
| #ifdef ENABLE_FX25 | |||
| else if(txFrame[txFrameTail].fx25Mode != NULL) | |||
| { | |||
| __disable_irq(); | |||
| txFrameBufferFull = false; | |||
| txFrameTail++; | |||
| txFrameTail %= FRAME_MAX_COUNT; | |||
| txByteIdx = 0; | |||
| __enable_irq(); | |||
| if((txFrameHead != txFrameTail) || txFrameBufferFull) | |||
| { | |||
| if(txFrame[txFrameTail].fx25Mode != NULL) | |||
| { | |||
| txStage = TX_STAGE_CORRELATION_TAG; | |||
| txTagByteIdx = 0; | |||
| goto transmitTag; | |||
| } | |||
| else | |||
| goto transmitNormalData; | |||
| } | |||
| else | |||
| goto transmitTail; | |||
| } | |||
| #endif | |||
| else | |||
| { | |||
| txStage = TX_STAGE_CRC; //transmit CRC | |||
| txCrcByteIdx = 0; | |||
| } | |||
| } | |||
| else //no more frames | |||
| { | |||
| transmitTail: | |||
| __enable_irq(); | |||
| txByteIdx = 0; | |||
| txBitIdx = 0; | |||
| txStage = TX_STAGE_TAIL; | |||
| } | |||
| } | |||
| if(txStage == TX_STAGE_CRC) //transmitting CRC | |||
| { | |||
| if(txCrcByteIdx <= 1) | |||
| { | |||
| txByte = (txCrc & 0xFF) ^ 0xFF; | |||
| txCrc >>= 8; | |||
| txCrcByteIdx++; | |||
| } | |||
| else | |||
| { | |||
| txCrc = 0xFFFF; | |||
| txStage = TX_STAGE_FOOTER_FLAGS; //now transmit flags | |||
| txFlagsElapsed = 0; | |||
| } | |||
| } | |||
| if(txStage == TX_STAGE_FOOTER_FLAGS) | |||
| { | |||
| if(txFlagsElapsed < STATIC_FOOTER_FLAG_COUNT) | |||
| { | |||
| txByte = 0x7E; | |||
| txFlagsElapsed++; | |||
| } | |||
| else | |||
| { | |||
| txFlagsElapsed = 0; | |||
| __disable_irq(); | |||
| txFrameBufferFull = false; | |||
| txFrameTail++; | |||
| txFrameTail %= FRAME_MAX_COUNT; | |||
| txByteIdx = 0; | |||
| #ifdef ENABLE_FX25 | |||
| if(((txFrameHead != txFrameTail) || txFrameBufferFull) && (txFrame[txFrameTail].fx25Mode != NULL)) | |||
| { | |||
| __enable_irq(); | |||
| txStage = TX_STAGE_CORRELATION_TAG; | |||
| txTagByteIdx = 0; | |||
| goto transmitTag; | |||
| } | |||
| #endif | |||
| __enable_irq(); | |||
| txStage = TX_STAGE_DATA; //return to normal data transmission stage. There might be a next frame to transmit | |||
| goto transmitNormalData; | |||
| } | |||
| } | |||
| if(txStage == TX_STAGE_TAIL) //transmitting tail | |||
| { | |||
| if(txTailElapsed < txTail) | |||
| { | |||
| txByte = SYNC_BYTE; | |||
| txTailElapsed++; | |||
| } | |||
| else //tail transmitted, stop transmission | |||
| { | |||
| txTailElapsed = 0; | |||
| txStage = TX_STAGE_IDLE; | |||
| txCrc = 0xFFFF; | |||
| txBitstuff = 0; | |||
| txByte = 0; | |||
| txInitStage = TX_INIT_OFF; | |||
| txBufferTail = txBufferHead; | |||
| ModemTransmitStop(); | |||
| return 0; | |||
| } | |||
| } | |||
| } | |||
| uint8_t txBit = 0; | |||
| //transmitting normal data or CRC in AX.25 mode | |||
| if( | |||
| #ifdef ENABLE_FX25 | |||
| (NULL == txFrame[txFrameTail].fx25Mode) && | |||
| #endif | |||
| ((txStage == TX_STAGE_DATA) || (txStage == TX_STAGE_CRC))) | |||
| { | |||
| if(txBitstuff == 5) //5 consecutive ones transmitted | |||
| { | |||
| txBit = 0; //transmit bit-stuffed 0 | |||
| txBitstuff = 0; | |||
| } | |||
| else | |||
| { | |||
| if(txByte & 1) //1 being transmitted | |||
| { | |||
| txBitstuff++; //increment bit stuffing counter | |||
| txBit = 1; | |||
| } | |||
| else | |||
| { | |||
| txBit = 0; | |||
| txBitstuff = 0; //0 being transmitted, reset bit stuffing counter | |||
| } | |||
| if(txStage == TX_STAGE_DATA) //calculate CRC only for normal data | |||
| calculateCRC(txByte & 1, &txCrc); | |||
| txByte >>= 1; | |||
| txBitIdx++; | |||
| } | |||
| } | |||
| //transmitting in FX.25 mode or in AX.25 mode, but these are preamble or flags, don't calculate CRC, don't use bit stuffing | |||
| else | |||
| { | |||
| txBit = txByte & 1; | |||
| txByte >>= 1; | |||
| txBitIdx++; | |||
| } | |||
| return txBit; | |||
| } | |||
| /** | |||
| * @brief Initialize transmission and start when possible | |||
| */ | |||
| void Ax25TransmitBuffer(void) | |||
| { | |||
| if(txInitStage == TX_INIT_WAITING) | |||
| return; | |||
| if(txInitStage == TX_INIT_TRANSMITTING) | |||
| return; | |||
| if((txFrameHead != txFrameTail) || txFrameBufferFull) | |||
| { | |||
| txQuiet = (SysTickGet() + (Ax25Config.quietTime / SYSTICK_INTERVAL) + Random(0, 200 / SYSTICK_INTERVAL)); //calculate required delay | |||
| txInitStage = TX_INIT_WAITING; | |||
| } | |||
| } | |||
| /** | |||
| * @brief Start transmission immediately | |||
| * @warning Transmission should be initialized using Ax25_transmitBuffer | |||
| */ | |||
| static void transmitStart(void) | |||
| { | |||
| txCrc = 0xFFFF; //initial CRC value | |||
| txStage = TX_STAGE_PREAMBLE; | |||
| txByte = 0; | |||
| txBitIdx = 0; | |||
| txFlagsElapsed = 0; | |||
| ModemTransmitStart(); | |||
| } | |||
| /** | |||
| * @brief Start transmitting when possible | |||
| * @attention Must be continuously polled in main loop | |||
| */ | |||
| void Ax25TransmitCheck(void) | |||
| { | |||
| if(txInitStage == TX_INIT_OFF) //TX not initialized at all, nothing to transmit | |||
| return; | |||
| if(txInitStage == TX_INIT_TRANSMITTING) //already transmitting | |||
| return; | |||
| if(ModemIsTxTestOngoing()) //TX test is enabled, wait for now | |||
| return; | |||
| if(txQuiet < SysTickGet()) //quit time has elapsed | |||
| { | |||
| if(!ModemDcdState()) //channel is free | |||
| { | |||
| txInitStage = TX_INIT_TRANSMITTING; //transmit right now | |||
| txRetries = 0; | |||
| transmitStart(); | |||
| } | |||
| else //channel is busy | |||
| { | |||
| if(txRetries == MAX_TRANSMIT_RETRY_COUNT) //timeout | |||
| { | |||
| txInitStage = TX_INIT_TRANSMITTING; //transmit right now | |||
| txRetries = 0; | |||
| transmitStart(); | |||
| } | |||
| else //still trying | |||
| { | |||
| txQuiet = SysTickGet() + Random(100 / SYSTICK_INTERVAL, 500 / SYSTICK_INTERVAL); //try again after some random time | |||
| txRetries++; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| void Ax25Init(void) | |||
| { | |||
| txCrc = 0xFFFF; | |||
| memset((void*)rxState, 0, sizeof(rxState)); | |||
| for(uint8_t i = 0; i < (sizeof(rxState) / sizeof(rxState[0])); i++) | |||
| rxState[i].crc = 0xFFFF; | |||
| txDelay = ((float)Ax25Config.txDelayLength / (8.f * 1000.f / ModemGetBaudrate())); //change milliseconds to byte count | |||
| txTail = ((float)Ax25Config.txTailLength / (8.f * 1000.f / ModemGetBaudrate())); | |||
| } | |||
| @ -0,0 +1,147 @@ | |||
| /* | |||
| Copyright 2020-2023 Piotr Wilkon | |||
| This file is part of VP-Digi. | |||
| VP-Digi 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. | |||
| VP-Digi 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 VP-Digi. If not, see <http://www.gnu.org/licenses/>. | |||
| */ | |||
| #ifdef ENABLE_FX25 | |||
| #include "fx25.h" | |||
| #include <stddef.h> | |||
| #include "rs.h" | |||
| #define FX25_RS_FCR 1 | |||
| #define FX25_PREGENERATE_POLYS | |||
| #define FX25_MAX_DISTANCE 10 //maximum Hamming distance when comparing tags | |||
| const struct Fx25Mode Fx25ModeList[11] = | |||
| { | |||
| {.tag = 0xB74DB7DF8A532F3E, .K = 239, .T = 16}, | |||
| {.tag = 0x26FF60A600CC8FDE, .K = 128, .T = 16}, | |||
| {.tag = 0xC7DC0508F3D9B09E, .K = 64, .T = 16}, | |||
| {.tag = 0x8F056EB4369660EE, .K = 32, .T = 16}, | |||
| {.tag = 0x6E260B1AC5835FAE, .K = 223, .T = 32}, | |||
| {.tag = 0xFF94DC634F1CFF4E, .K = 128, .T = 32}, | |||
| {.tag = 0x1EB7B9CDBC09C00E, .K = 64, .T = 32}, | |||
| {.tag = 0xDBF869BD2DBB1776, .K = 32, .T = 32}, | |||
| {.tag = 0x3ADB0C13DEAE2836, .K = 191, .T = 64}, | |||
| {.tag = 0xAB69DB6A543188D6, .K = 128, .T = 64}, | |||
| {.tag = 0x4A4ABEC4A724B796, .K = 64, .T = 64} | |||
| }; | |||
| const struct Fx25Mode* Fx25GetModeForTag(uint64_t tag) | |||
| { | |||
| for(uint8_t i = 0; i < sizeof(Fx25ModeList) / sizeof(*Fx25ModeList); i++) | |||
| { | |||
| if(__builtin_popcountll(tag ^ Fx25ModeList[i].tag) <= FX25_MAX_DISTANCE) | |||
| return &Fx25ModeList[i]; | |||
| } | |||
| return NULL; | |||
| } | |||
| const struct Fx25Mode* Fx25GetModeForSize(uint16_t size) | |||
| { | |||
| //use "UZ7HO Soundmodem standard" for choosing FX.25 mode | |||
| if(size <= 32) | |||
| return &Fx25ModeList[3]; | |||
| else if(size <= 64) | |||
| return &Fx25ModeList[2]; | |||
| else if(size <= 128) | |||
| return &Fx25ModeList[5]; | |||
| else if(size <= 191) | |||
| return &Fx25ModeList[8]; | |||
| else if(size <= 223) | |||
| return &Fx25ModeList[4]; | |||
| else if(size <= 239) | |||
| return &Fx25ModeList[0]; | |||
| else | |||
| return NULL; //frame too big, do not use FX.25 | |||
| } | |||
| #ifdef FX25_PREGENERATE_POLYS | |||
| static struct LwFecRS rs16, rs32, rs64; | |||
| #else | |||
| static struct LwFecRS rs; | |||
| #endif | |||
| void Fx25Encode(uint8_t *buffer, const struct Fx25Mode *mode) | |||
| { | |||
| #ifdef FX25_PREGENERATE_POLYS | |||
| struct LwFecRS *rs = NULL; | |||
| switch(mode->T) | |||
| { | |||
| case 16: | |||
| rs = &rs16; | |||
| break; | |||
| case 32: | |||
| rs = &rs32; | |||
| break; | |||
| case 64: | |||
| rs = &rs64; | |||
| break; | |||
| default: | |||
| rs = &rs16; | |||
| break; | |||
| } | |||
| RsEncode(rs, buffer, mode->K); | |||
| #else | |||
| RsInit(&rs, mode->T, FX25_RS_FCR); | |||
| RsEncode(&rs, buffer, mode->K); | |||
| #endif | |||
| } | |||
| bool Fx25Decode(uint8_t *buffer, const struct Fx25Mode *mode, uint8_t *fixed) | |||
| { | |||
| #ifdef FX25_PREGENERATE_POLYS | |||
| struct LwFecRS *rs = NULL; | |||
| switch(mode->T) | |||
| { | |||
| case 16: | |||
| rs = &rs16; | |||
| break; | |||
| case 32: | |||
| rs = &rs32; | |||
| break; | |||
| case 64: | |||
| rs = &rs64; | |||
| break; | |||
| default: | |||
| rs = &rs16; | |||
| break; | |||
| } | |||
| return RsDecode(rs, buffer, mode->K, fixed); | |||
| #else | |||
| RsInit(&rs, mode->T, FX25_RS_FCR); | |||
| return RsDecode(&rs, buffer, mode->K, fixed); | |||
| #endif | |||
| } | |||
| void Fx25Init(void) | |||
| { | |||
| #ifdef FX25_PREGENERATE_POLYS | |||
| RsInit(&rs16, 16, FX25_RS_FCR); | |||
| RsInit(&rs32, 32, FX25_RS_FCR); | |||
| RsInit(&rs64, 64, FX25_RS_FCR); | |||
| #else | |||
| #endif | |||
| } | |||
| #endif | |||
| @ -0,0 +1,897 @@ | |||
| /* | |||
| Copyright 2020-2023 Piotr Wilkon | |||
| This file is part of VP-Digi. | |||
| VP-Digi 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. | |||
| VP-Digi 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 VP-Digi. If not, see <http://www.gnu.org/licenses/>. | |||
| */ | |||
| #include <string.h> | |||
| #include <math.h> | |||
| #include "modem.h" | |||
| #include <stdlib.h> | |||
| #include <stdbool.h> | |||
| #include "ax25.h" | |||
| #include "common.h" | |||
| #include "systick.h" | |||
| #include "drivers/modem_ll.h" | |||
| /* | |||
| * Configuration for PLL-based data carrier detection | |||
| * 1. MAXPULSE - the maximum value of the DCD pulse counter. Higher values allow for more stability when a correct signal is detected, | |||
| * but introduce a delay when releasing DCD | |||
| * 2. THRES - the threshold value of the DCD pulse counter. When reached the input signal is assumed to be valid. Higher values mean more immunity to noise, | |||
| * but introduce delay when setting DCD | |||
| * 3. MAXPULSE and THRES difference sets the DCD "inertia" so that the DCD state won't change rapidly when a valid signal is present | |||
| * 4. INC is the DCD pulse counter incrementation value when symbol changes near the PLL counter zero | |||
| * 5. DEC is the DCD pulse counter decrementation value when symbol changes too far from PLL counter zero | |||
| * 6. TUNE is the PLL counter tuning coefficient. It is applied when there is a symbol change (as the symbol change should occur when the PLL counter crosses zero) | |||
| * | |||
| * [ DCD OFF * | DCD ON ] | |||
| * 0 COUNTER THRES MAXPULSE | |||
| * <-DEC INC-> | |||
| * | |||
| * The DCD mechanism is described in demodulate(). | |||
| * All values were selected by trial and error | |||
| */ | |||
| #define DCD1200_MAXPULSE 60 | |||
| #define DCD1200_THRES 20 | |||
| #define DCD1200_INC 2 | |||
| #define DCD1200_DEC 1 | |||
| #define DCD1200_TUNE 0.74f | |||
| #define DCD9600_MAXPULSE 60 | |||
| #define DCD9600_THRES 40 | |||
| #define DCD9600_INC 1 | |||
| #define DCD9600_DEC 1 | |||
| #define DCD9600_TUNE 0.74f | |||
| #define DCD300_MAXPULSE 80 | |||
| #define DCD300_THRES 20 | |||
| #define DCD300_INC 4 | |||
| #define DCD300_DEC 1 | |||
| #define DCD300_TUNE 0.74f | |||
| #define N1200 8 //samples per symbol @ fs=9600, oversampling = 38400 Hz | |||
| #define N9600 4 //fs=38400, oversampling = 153600 Hz | |||
| #define N300 32 //fs=9600, oversampling = 38400 Hz | |||
| #define NMAX 32 //keep this value equal to the biggest Nx | |||
| #define PLL1200_STEP (((uint64_t)1 << 32) / N1200) //PLL tick increment value | |||
| #define PLL9600_STEP (((uint64_t)1 << 32) / N9600) | |||
| #define PLL300_STEP (((uint64_t)1 << 32) / N300) | |||
| #define PLL1200_LOCKED_TUNE 0.74f | |||
| #define PLL1200_NOT_LOCKED_TUNE 0.50f | |||
| #define PLL9600_LOCKED_TUNE 0.89f | |||
| #define PLL9600_NOT_LOCKED_TUNE 0.50f //I have 0.67 noted somewhere as possibly better value | |||
| #define PLL300_LOCKED_TUNE 0.74f | |||
| #define PLL300_NOT_LOCKED_TUNE 0.50f | |||
| #define AMP_TRACKING_ATTACK 0.16f //0.16 | |||
| #define AMP_TRACKING_DECAY 0.00004f //0.00004 | |||
| #define DAC_SINE_SIZE 128 //DAC sine table size | |||
| #define PLL_TUNE_BITS 8 //number of bits when tuning PLL to avoid floating point operations | |||
| struct ModemDemodConfig ModemConfig; | |||
| static uint8_t N; //samples per symbol | |||
| static enum ModemTxTestMode txTestState; //current TX test mode | |||
| static uint8_t demodCount; //actual number of parallel demodulators | |||
| static uint16_t dacSine[DAC_SINE_SIZE]; //sine samples for DAC | |||
| static uint8_t dacSineIdx; //current sine sample index | |||
| static volatile uint16_t samples[MODEM_LL_OVERSAMPLING_FACTOR]; //very raw received samples, filled directly by DMA | |||
| static uint8_t currentSymbol; //current symbol for NRZI encoding | |||
| static uint8_t scrambledSymbol; //current symbol after scrambling | |||
| static float markFreq; //mark frequency | |||
| static float spaceFreq; //space frequency | |||
| static float baudRate; //baudrate | |||
| static uint8_t markStep; //mark timer step | |||
| static uint8_t spaceStep; //space timer step | |||
| static uint16_t baudRateStep; //baudrate timer step | |||
| static int16_t coeffHiI[NMAX], coeffLoI[NMAX], coeffHiQ[NMAX], coeffLoQ[NMAX]; //correlator IQ coefficients | |||
| static uint8_t dcd = 0; //multiplexed DCD state from both demodulators | |||
| static uint32_t lfsr = 0xFFFFF; //LFSR for 9600 Bd | |||
| /** | |||
| * @brief BPF filter with 2200 Hz tone 6 dB preemphasis (it actually attenuates 1200 Hz tone by 6 dB) | |||
| */ | |||
| static const int16_t bpf1200[8] = | |||
| { | |||
| 728, | |||
| -13418, | |||
| -554, | |||
| 19493, | |||
| -554, | |||
| -13418, | |||
| 728, | |||
| 2104 | |||
| }; | |||
| /** | |||
| * @brief BPF filter with 2200 Hz tone 6 dB deemphasis | |||
| */ | |||
| static const int16_t bpf1200Inv[8] = | |||
| { | |||
| -10513, | |||
| -10854, | |||
| 9589, | |||
| 23884, | |||
| 9589, | |||
| -10854, | |||
| -10513, | |||
| -879 | |||
| }; | |||
| //fs=9600, rectangular, fc1=1500, fc2=1900, 0 dB @ 1600 Hz and 1800 Hz, N = 15, gain 65536 | |||
| static const int16_t bpf300[15] = | |||
| { | |||
| 186, 8887, 8184, -1662, -10171, -8509, 386, 5394, 386, -8509, -10171, -1662, 8184, 8887, 186, | |||
| }; | |||
| #define BPF_MAX_TAPS 15 | |||
| //fs=9600 Hz, raised cosine, fc=300 Hz (BR=600 Bd), beta=0.8, N=14, gain=65536 | |||
| static const int16_t lpf300[14] = | |||
| { | |||
| 4385, 4515, 4627, 4720, 4793, 4846, 4878, 4878, 4846, 4793, 4720, 4627, 4515, 4385, | |||
| }; | |||
| //I don't remember what are this filter parameters, | |||
| //but it seems to be the best among all I have tested | |||
| static const int16_t lpf1200[15] = | |||
| { | |||
| -6128, | |||
| -5974, | |||
| -2503, | |||
| 4125, | |||
| 12679, | |||
| 21152, | |||
| 27364, | |||
| 29643, | |||
| 27364, | |||
| 21152, | |||
| 12679, | |||
| 4125, | |||
| -2503, | |||
| -5974, | |||
| -6128 | |||
| }; | |||
| //fs=38400 Hz, Gaussian, fc=4800 Hz (9600 Bd), N=9, gain=65536 | |||
| //seems like there is almost no difference between N=9 and any higher order | |||
| static const int16_t lpf9600[9] = {497, 2360, 7178, 13992, 17478, 13992, 7178, 2360, 497}; | |||
| #define LPF_MAX_TAPS 15 | |||
| #define FILTER_MAX_TAPS ((LPF_MAX_TAPS > BPF_MAX_TAPS) ? LPF_MAX_TAPS : BPF_MAX_TAPS) | |||
| struct Filter | |||
| { | |||
| int16_t *coeffs; | |||
| uint8_t taps; | |||
| int32_t samples[FILTER_MAX_TAPS]; | |||
| uint8_t gainShift; | |||
| }; | |||
| struct DemodState | |||
| { | |||
| uint8_t rawSymbols; //raw, unsynchronized symbols | |||
| uint8_t syncSymbols; //synchronized symbols | |||
| enum ModemPrefilter prefilter; | |||
| struct Filter bpf; | |||
| int16_t correlatorSamples[NMAX]; | |||
| uint8_t correlatorSamplesIdx; | |||
| struct Filter lpf; | |||
| uint8_t dcd : 1; //DCD state | |||
| int32_t pll; //bit recovery PLL counter | |||
| int32_t pllStep; | |||
| int32_t pllLockedTune; | |||
| int32_t pllNotLockedTune; | |||
| int32_t dcdPll; //DCD PLL main counter | |||
| uint8_t dcdLastSymbol; //last symbol for DCD | |||
| uint16_t dcdCounter; //DCD "pulse" counter (incremented when RX signal is correct) | |||
| uint16_t dcdMax; | |||
| uint16_t dcdThres; | |||
| uint16_t dcdInc; | |||
| uint16_t dcdDec; | |||
| int32_t dcdTune; | |||
| int16_t peak; | |||
| int16_t valley; | |||
| }; | |||
| static struct DemodState demodState[MODEM_MAX_DEMODULATOR_COUNT]; | |||
| static void decode(uint8_t symbol, uint8_t demod); | |||
| static int32_t demodulate(int16_t sample, struct DemodState *dem); | |||
| static void setPtt(bool state); | |||
| static int32_t filter(struct Filter *filter, int32_t input) | |||
| { | |||
| int32_t out = 0; | |||
| for(uint8_t i = filter->taps - 1; i > 0; i--) | |||
| filter->samples[i] = filter->samples[i - 1]; //shift old samples | |||
| filter->samples[0] = input; //store new sample | |||
| for(uint8_t i = 0; i < filter->taps; i++) | |||
| { | |||
| out += (int32_t)filter->coeffs[i] * filter->samples[i]; | |||
| } | |||
| return out >> filter->gainShift; | |||
| } | |||
| float ModemGetBaudrate(void) | |||
| { | |||
| return baudRate; | |||
| } | |||
| uint8_t ModemGetDemodulatorCount(void) | |||
| { | |||
| return demodCount; | |||
| } | |||
| uint8_t ModemDcdState(void) | |||
| { | |||
| return dcd; | |||
| } | |||
| uint8_t ModemIsTxTestOngoing(void) | |||
| { | |||
| if(txTestState != TEST_DISABLED) | |||
| return 1; | |||
| return 0; | |||
| } | |||
| void ModemGetSignalLevel(uint8_t modem, int8_t *peak, int8_t *valley, uint8_t *level) | |||
| { | |||
| *peak = (100 * (int32_t)demodState[modem].peak) >> 12; | |||
| *valley = (100 * (int32_t)demodState[modem].valley) >> 12; | |||
| *level = (100 * (int32_t)(demodState[modem].peak - demodState[modem].valley)) >> 13; | |||
| } | |||
| enum ModemPrefilter ModemGetFilterType(uint8_t modem) | |||
| { | |||
| return demodState[modem].prefilter; | |||
| } | |||
| /** | |||
| * @brief Set DCD LED | |||
| * @param[in] state False - OFF, true - ON | |||
| */ | |||
| static void setDcd(bool state) | |||
| { | |||
| if(state) | |||
| { | |||
| MODEM_LL_DCD_LED_ON(); | |||
| } | |||
| else | |||
| { | |||
| MODEM_LL_DCD_LED_OFF(); | |||
| } | |||
| } | |||
| static inline uint8_t descramble(uint8_t in) | |||
| { | |||
| //G3RUH descrambling (x^17+x^12+1) | |||
| uint8_t bit = ((lfsr & 0x10000) > 0) ^ ((lfsr & 0x800) > 0) ^ (in > 0); | |||
| lfsr <<= 1; | |||
| lfsr |= in; | |||
| return bit; | |||
| } | |||
| static inline uint8_t scramble(uint8_t in) | |||
| { | |||
| //G3RUH scrambling (x^17+x^12+1) | |||
| uint8_t bit = ((lfsr & 0x10000) > 0) ^ ((lfsr & 0x800) > 0) ^ (in > 0); | |||
| lfsr <<= 1; | |||
| lfsr |= bit; | |||
| return bit; | |||
| } | |||
| /** | |||
| * @brief ISR for demodulator | |||
| */ | |||
| void MODEM_LL_DMA_INTERRUPT_HANDLER(void) __attribute__ ((interrupt)); | |||
| void MODEM_LL_DMA_INTERRUPT_HANDLER(void) | |||
| { | |||
| if(MODEM_LL_DMA_TRANSFER_COMPLETE_FLAG) | |||
| { | |||
| MODEM_LL_DMA_CLEAR_TRANSFER_COMPLETE_FLAG(); | |||
| //each sample is 12 bits, output sample is 13 bits | |||
| int32_t sample = ((samples[0] + samples[1] + samples[2] + samples[3]) >> 1) - 4095; //calculate input sample (decimation) | |||
| bool partialDcd = false; | |||
| for(uint8_t i = 0; i < demodCount; i++) | |||
| { | |||
| uint8_t symbol = (demodulate(sample, (struct DemodState*)&demodState[i]) > 0); //demodulate sample | |||
| decode(symbol, i); //recover bits, decode NRZI and call higher level function | |||
| if(demodState[i].dcd) | |||
| partialDcd = true; | |||
| } | |||
| if(partialDcd) //DCD on any of the demodulators | |||
| { | |||
| dcd = 1; | |||
| setDcd(true); | |||
| } | |||
| else //no DCD on both demodulators | |||
| { | |||
| dcd = 0; | |||
| setDcd(false); | |||
| } | |||
| } | |||
| } | |||
| /** | |||
| * @brief ISR for pushing DAC samples | |||
| */ | |||
| void MODEM_LL_DAC_INTERRUPT_HANDLER(void) __attribute__ ((interrupt)); | |||
| void MODEM_LL_DAC_INTERRUPT_HANDLER(void) | |||
| { | |||
| MODEM_LL_DAC_TIMER_CLEAR_INTERRUPT_FLAG; | |||
| int32_t sample = 0; | |||
| if(ModemConfig.modem == MODEM_9600) | |||
| { | |||
| if(ModemConfig.usePWM) | |||
| sample = scrambledSymbol ? 256 : 1; | |||
| else | |||
| sample = scrambledSymbol ? 15 : 0; | |||
| sample = filter(&demodState[0].lpf, sample); | |||
| } | |||
| else | |||
| { | |||
| sample = dacSine[dacSineIdx]; | |||
| dacSineIdx++; | |||
| dacSineIdx %= DAC_SINE_SIZE; | |||
| } | |||
| if(ModemConfig.usePWM) | |||
| { | |||
| MODEM_LL_PWM_PUT_VALUE(sample); | |||
| } | |||
| else | |||
| { | |||
| MODEM_LL_R2R_PUT_VALUE(sample); | |||
| } | |||
| } | |||
| /** | |||
| * @brief ISR for baudrate generator timer. NRZI encoding is done here. | |||
| */ | |||
| void MODEM_LL_BAUDRATE_TIMER_INTERRUPT_HANDLER(void) __attribute__ ((interrupt)); | |||
| void MODEM_LL_BAUDRATE_TIMER_INTERRUPT_HANDLER(void) | |||
| { | |||
| MODEM_LL_BAUDRATE_TIMER_CLEAR_INTERRUPT_FLAG(); | |||
| if(txTestState == TEST_DISABLED) //transmitting normal data | |||
| { | |||
| if(Ax25GetTxBit() == 0) //get next bit and check if it's 0 | |||
| { | |||
| currentSymbol ^= 1; //change symbol - NRZI encoding | |||
| } | |||
| //if 1, no symbol change | |||
| } | |||
| else //transmit test mode | |||
| { | |||
| if(ModemConfig.modem == MODEM_9600) | |||
| { | |||
| scrambledSymbol ^= 1; | |||
| return; | |||
| } | |||
| currentSymbol ^= 1; //change symbol | |||
| } | |||
| if(ModemConfig.modem == MODEM_9600) | |||
| { | |||
| scrambledSymbol = scramble(currentSymbol); | |||
| } | |||
| else | |||
| { | |||
| MODEM_LL_DAC_TIMER_SET_CURRENT_VALUE(0); | |||
| if(currentSymbol) | |||
| { | |||
| MODEM_LL_DAC_TIMER_SET_RELOAD_VALUE(spaceStep); | |||
| } | |||
| else | |||
| { | |||
| MODEM_LL_DAC_TIMER_SET_RELOAD_VALUE(markStep); | |||
| } | |||
| } | |||
| } | |||
| /** | |||
| * @brief Demodulate received sample (4x oversampling) | |||
| * @param[in] sample Received sample, no more than 13 bits | |||
| * @param[in] *dem Demodulator state | |||
| * @return Current tone (0 or 1) | |||
| */ | |||
| static int32_t demodulate(int16_t sample, struct DemodState *dem) | |||
| { | |||
| //input signal amplitude tracking | |||
| if(sample >= dem->peak) | |||
| { | |||
| dem->peak += (((int32_t)(AMP_TRACKING_ATTACK * (float)32768) * (int32_t)(sample - dem->peak)) >> 15); | |||
| } | |||
| else | |||
| { | |||
| dem->peak += (((int32_t)(AMP_TRACKING_DECAY * (float)32768) * (int32_t)(sample - dem->peak)) >> 15); | |||
| } | |||
| if(sample <= dem->valley) | |||
| { | |||
| dem->valley -= (((int32_t)(AMP_TRACKING_ATTACK * (float)32768) * (int32_t)(dem->valley - sample)) >> 15); | |||
| } | |||
| else | |||
| { | |||
| dem->valley -= (((int32_t)(AMP_TRACKING_DECAY * (float)32768) * (int32_t)(dem->valley - sample)) >> 15); | |||
| } | |||
| if(ModemConfig.modem != MODEM_9600) | |||
| { | |||
| if(dem->prefilter != PREFILTER_NONE) //filter is used | |||
| { | |||
| dem->correlatorSamples[dem->correlatorSamplesIdx++] = filter(&dem->bpf, sample); | |||
| } | |||
| else //no pre/deemphasis | |||
| { | |||
| dem->correlatorSamples[dem->correlatorSamplesIdx++] = sample; | |||
| } | |||
| dem->correlatorSamplesIdx %= N; | |||
| int32_t outLoI = 0, outLoQ = 0, outHiI = 0, outHiQ = 0; //output values after correlating | |||
| for(uint8_t i = 0; i < N; i++) | |||
| { | |||
| int16_t t = dem->correlatorSamples[(dem->correlatorSamplesIdx + i) % N]; //read sample | |||
| outLoI += t * coeffLoI[i]; //correlate sample | |||
| outLoQ += t * coeffLoQ[i]; | |||
| outHiI += t * coeffHiI[i]; | |||
| outHiQ += t * coeffHiQ[i]; | |||
| } | |||
| outHiI >>= 14; | |||
| outHiQ >>= 14; | |||
| outLoI >>= 14; | |||
| outLoQ >>= 14; | |||
| sample = (abs(outLoI) + abs(outLoQ)) - (abs(outHiI) + abs(outHiQ)); | |||
| } | |||
| //DCD using "PLL" | |||
| //PLL is running nominally at the frequency equal to the baudrate | |||
| //PLL timer is counting up and eventually overflows to a minimal negative value | |||
| //so it crosses zero in the middle | |||
| //tone change should happen somewhere near this zero-crossing (in ideal case of exactly same TX and RX baudrates) | |||
| //nothing is ideal, so we need to have some region around zero where tone change is expected | |||
| //however in case of noise the demodulated output is completely random and has many symbol changes in different places | |||
| //other than the PLL zero-crossing, thus making it easier to utilize this mechanism | |||
| //if tone changed inside this region, then we add something to the DCD pulse counter and adjust counter phase for the counter to be closer to 0 | |||
| //if tone changes outside this region, then we subtract something from the DCD pulse counter | |||
| //if some DCD pulse threshold is reached, then we claim that the incoming signal is correct and set DCD flag | |||
| //when configured properly, it's generally immune to noise and sensitive to correct signal | |||
| //it's also important to set some maximum value for DCD counter, otherwise the DCD is "sticky" | |||
| dem->dcdPll = (int32_t)((uint32_t)(dem->dcdPll) + (uint32_t)(dem->pllStep)); //keep PLL ticking at the frequency equal to baudrate | |||
| if((sample > 0) != dem->dcdLastSymbol) //tone changed | |||
| { | |||
| if((uint32_t)abs(dem->dcdPll) < (uint32_t)(dem->pllStep)) //tone change occurred near zero | |||
| { | |||
| dem->dcdCounter += dem->dcdInc; //increase DCD counter | |||
| if(dem->dcdCounter > dem->dcdMax) //maximum DCD counter value reached | |||
| dem->dcdCounter = dem->dcdMax; //avoid "sticky" DCD and counter overflow | |||
| } | |||
| else //tone change occurred far from zero | |||
| { | |||
| if(dem->dcdCounter >= dem->dcdDec) //avoid overflow | |||
| dem->dcdCounter -= dem->dcdDec; //decrease DCD counter | |||
| else | |||
| dem->dcdCounter = 0; | |||
| } | |||
| //avoid floating point operations | |||
| dem->dcdPll = ((int64_t)dem->dcdPll * (int64_t)dem->dcdTune) >> PLL_TUNE_BITS; | |||
| } | |||
| dem->dcdLastSymbol = sample > 0; //store last symbol for symbol change detection | |||
| if(dem->dcdCounter > dem->dcdThres) //DCD threshold reached | |||
| dem->dcd = 1; //DCD! | |||
| else //below DCD threshold | |||
| dem->dcd = 0; //no DCD | |||
| return filter(&dem->lpf, sample) > 0; | |||
| } | |||
| /** | |||
| * @brief Decode received symbol: bit recovery, NRZI decoding and pass the decoded bit to higher level protocol | |||
| * @param[in] symbol Received symbol | |||
| * @param demod Demodulator index | |||
| */ | |||
| static void decode(uint8_t symbol, uint8_t demod) | |||
| { | |||
| struct DemodState *dem = (struct DemodState*)&demodState[demod]; | |||
| //This function provides bit/clock recovery and NRZI decoding | |||
| //Bit recovery is based on PLL which is described in the function above (DCD PLL) | |||
| //Current symbol is sampled at PLL counter overflow, so symbol transition should occur at PLL counter zero | |||
| int32_t previous = dem->pll; //store last clock state | |||
| dem->pll = (int32_t)((uint32_t)(dem->pll) + (uint32_t)(dem->pllStep)); //keep PLL running | |||
| dem->rawSymbols <<= 1; //store received unsynchronized symbol | |||
| dem->rawSymbols |= (symbol & 1); | |||
| if ((dem->pll < 0) && (previous > 0)) //PLL counter overflow, sample symbol, decode NRZI and process in higher layer | |||
| { | |||
| dem->syncSymbols <<= 1; //shift recovered (received, synchronized) bit register | |||
| uint8_t sym = dem->rawSymbols & 0x07; //take last three symbols for sampling. Seems that 1 symbol is not enough, but 3 symbols work well | |||
| if(sym == 0b111 || sym == 0b110 || sym == 0b101 || sym == 0b011) //if there are 2 or 3 ones, then the received symbol is 1 | |||
| sym = 1; | |||
| else | |||
| sym = 0; | |||
| if(ModemConfig.modem == MODEM_9600) | |||
| sym = descramble(sym); //descramble | |||
| dem->syncSymbols |= sym; | |||
| //NRZI decoding | |||
| if (((dem->syncSymbols & 0x03) == 0b11) || ((dem->syncSymbols & 0x03) == 0b00)) //two last symbols are the same - no symbol transition - decoded bit 1 | |||
| { | |||
| Ax25BitParse(1, demod); | |||
| } | |||
| else //symbol transition - decoded bit 0 | |||
| { | |||
| Ax25BitParse(0, demod); | |||
| } | |||
| } | |||
| if(((dem->rawSymbols & 0x03) == 0b10) || ((dem->rawSymbols & 0x03) == 0b01)) //if there was a symbol transition, adjust PLL | |||
| { | |||
| //avoid floating point operations. Multiply by n-bit value and shift by n bits | |||
| if(!dem->dcd) //PLL not locked | |||
| { | |||
| dem->pll = ((int64_t)dem->pll * (int64_t)dem->pllNotLockedTune) >> PLL_TUNE_BITS; //adjust PLL faster | |||
| } | |||
| else //PLL locked | |||
| { | |||
| dem->pll = ((int64_t)dem->pll * (int64_t)dem->pllLockedTune) >> PLL_TUNE_BITS; //adjust PLL slower | |||
| } | |||
| } | |||
| } | |||
| void ModemTxTestStart(enum ModemTxTestMode type) | |||
| { | |||
| if(txTestState != TEST_DISABLED) //TX test is already running | |||
| ModemTxTestStop(); //stop this test | |||
| setPtt(true); //PTT on | |||
| txTestState = type; | |||
| MODEM_LL_ADC_TIMER_DISABLE(); | |||
| MODEM_LL_DAC_TIMER_ENABLE(); | |||
| NVIC_DisableIRQ(MODEM_LL_DMA_IRQ); | |||
| NVIC_EnableIRQ(MODEM_LL_DAC_IRQ); | |||
| if(ModemConfig.modem == MODEM_9600) | |||
| { | |||
| MODEM_LL_DAC_TIMER_SET_RELOAD_VALUE(markStep); | |||
| MODEM_LL_BAUDRATE_TIMER_ENABLE(); | |||
| NVIC_EnableIRQ(MODEM_LL_BAUDRATE_TIMER_IRQ); | |||
| return; | |||
| } | |||
| if(type == TEST_MARK) | |||
| { | |||
| MODEM_LL_DAC_TIMER_SET_RELOAD_VALUE(markStep); | |||
| } | |||
| else if(type == TEST_SPACE) | |||
| { | |||
| MODEM_LL_DAC_TIMER_SET_RELOAD_VALUE(spaceStep); | |||
| } | |||
| else //alternating tones | |||
| { | |||
| MODEM_LL_BAUDRATE_TIMER_ENABLE(); | |||
| NVIC_EnableIRQ(MODEM_LL_BAUDRATE_TIMER_IRQ); //enable interrupt in NVIC | |||
| } | |||
| } | |||
| void ModemTxTestStop(void) | |||
| { | |||
| txTestState = TEST_DISABLED; | |||
| MODEM_LL_BAUDRATE_TIMER_DISABLE(); | |||
| MODEM_LL_DAC_TIMER_DISABLE(); //disable DAC timer | |||
| MODEM_LL_ADC_TIMER_ENABLE(); //enable RX timer | |||
| NVIC_DisableIRQ(MODEM_LL_BAUDRATE_TIMER_IRQ); | |||
| NVIC_DisableIRQ(MODEM_LL_DAC_IRQ); | |||
| NVIC_EnableIRQ(MODEM_LL_DMA_IRQ); | |||
| setPtt(false); //PTT off | |||
| } | |||
| void ModemTransmitStart(void) | |||
| { | |||
| setPtt(true); //PTT on | |||
| if(ModemConfig.modem == MODEM_9600) | |||
| { | |||
| MODEM_LL_DAC_TIMER_SET_RELOAD_VALUE(markStep); | |||
| } | |||
| MODEM_LL_BAUDRATE_TIMER_ENABLE(); | |||
| MODEM_LL_DAC_TIMER_ENABLE(); | |||
| MODEM_LL_ADC_TIMER_DISABLE(); | |||
| NVIC_DisableIRQ(MODEM_LL_DMA_IRQ); | |||
| NVIC_EnableIRQ(MODEM_LL_DAC_IRQ); | |||
| NVIC_EnableIRQ(MODEM_LL_BAUDRATE_TIMER_IRQ); | |||
| } | |||
| /** | |||
| * @brief Stop TX and go back to RX | |||
| */ | |||
| void ModemTransmitStop(void) | |||
| { | |||
| MODEM_LL_ADC_TIMER_ENABLE(); | |||
| MODEM_LL_DAC_TIMER_DISABLE(); | |||
| MODEM_LL_BAUDRATE_TIMER_DISABLE(); | |||
| NVIC_DisableIRQ(MODEM_LL_DAC_IRQ); | |||
| NVIC_DisableIRQ(MODEM_LL_BAUDRATE_TIMER_IRQ); | |||
| NVIC_EnableIRQ(MODEM_LL_DMA_IRQ); | |||
| setPtt(false); | |||
| } | |||
| /** | |||
| * @brief Controls PTT output | |||
| * @param state False - PTT off, true - PTT on | |||
| */ | |||
| static void setPtt(bool state) | |||
| { | |||
| if(state) | |||
| { | |||
| MODEM_LL_PTT_ON(); | |||
| } | |||
| else | |||
| { | |||
| MODEM_LL_PTT_OFF(); | |||
| } | |||
| } | |||
| /** | |||
| * @brief Initialize AFSK module | |||
| */ | |||
| void ModemInit(void) | |||
| { | |||
| memset(demodState, 0, sizeof(demodState)); | |||
| MODEM_LL_INITIALIZE_RCC(); //initialize peripheral clocks | |||
| MODEM_LL_INITIALIZE_OUTPUTS(); | |||
| MODEM_LL_INITIALIZE_ADC(); | |||
| MODEM_LL_INITIALIZE_DMA(samples); | |||
| NVIC_EnableIRQ(MODEM_LL_DMA_IRQ); | |||
| MODEM_LL_ADC_TIMER_INITIALIZE(); | |||
| MODEM_LL_DAC_TIMER_INITIALIZE(); | |||
| MODEM_LL_BAUDRATE_TIMER_INITIALIZE(); | |||
| if(ModemConfig.modem > MODEM_9600) | |||
| ModemConfig.modem = MODEM_1200; | |||
| if((ModemConfig.modem == MODEM_1200) || (ModemConfig.modem == MODEM_1200_V23)) | |||
| { | |||
| //use one modem in FX.25 mode | |||
| //FX.25 (RS) functions are not reentrant | |||
| if( | |||
| #ifdef ENABLE_FX25 | |||
| Ax25Config.fx25 | |||
| #else | |||
| 0 | |||
| #endif | |||
| ) | |||
| demodCount = 1; | |||
| else | |||
| demodCount = 2; | |||
| N = N1200; | |||
| baudRate = 1200.f; | |||
| demodState[0].pllStep = PLL1200_STEP; | |||
| demodState[0].pllLockedTune = PLL1200_LOCKED_TUNE * (float)((uint32_t)1 << PLL_TUNE_BITS); | |||
| demodState[0].pllNotLockedTune = PLL1200_NOT_LOCKED_TUNE * (float)((uint32_t)1 << PLL_TUNE_BITS); | |||
| demodState[0].dcdMax = DCD1200_MAXPULSE; | |||
| demodState[0].dcdThres = DCD1200_THRES; | |||
| demodState[0].dcdInc = DCD1200_INC; | |||
| demodState[0].dcdDec = DCD1200_DEC; | |||
| demodState[0].dcdTune = DCD1200_TUNE * (float)((uint32_t)1 << PLL_TUNE_BITS); | |||
| demodState[1].pllStep = PLL1200_STEP; | |||
| demodState[1].pllLockedTune = PLL1200_LOCKED_TUNE * (float)((uint32_t)1 << PLL_TUNE_BITS); | |||
| demodState[1].pllNotLockedTune = PLL1200_NOT_LOCKED_TUNE * (float)((uint32_t)1 << PLL_TUNE_BITS); | |||
| demodState[1].dcdMax = DCD1200_MAXPULSE; | |||
| demodState[1].dcdThres = DCD1200_THRES; | |||
| demodState[1].dcdInc = DCD1200_INC; | |||
| demodState[1].dcdDec = DCD1200_DEC; | |||
| demodState[1].dcdTune = DCD1200_TUNE * (float)((uint32_t)1 << PLL_TUNE_BITS); | |||
| demodState[1].prefilter = PREFILTER_NONE; | |||
| demodState[1].lpf.coeffs = (int16_t*)lpf1200; | |||
| demodState[1].lpf.taps = sizeof(lpf1200) / sizeof(*lpf1200); | |||
| demodState[1].lpf.gainShift = 15; | |||
| demodState[0].lpf.coeffs = (int16_t*)lpf1200; | |||
| demodState[0].lpf.taps = sizeof(lpf1200) / sizeof(*lpf1200); | |||
| demodState[0].lpf.gainShift = 15; | |||
| demodState[0].prefilter = PREFILTER_NONE; | |||
| if(ModemConfig.flatAudioIn) //when used with flat audio input, use deemphasis and flat modems | |||
| { | |||
| #ifdef ENABLE_FX25 | |||
| if(Ax25Config.fx25) | |||
| demodState[0].prefilter = PREFILTER_NONE; | |||
| else | |||
| #endif | |||
| demodState[0].prefilter = PREFILTER_DEEMPHASIS; | |||
| demodState[0].bpf.coeffs = (int16_t*)bpf1200Inv; | |||
| demodState[0].bpf.taps = sizeof(bpf1200Inv) / sizeof(*bpf1200Inv); | |||
| demodState[0].bpf.gainShift = 15; | |||
| } | |||
| else //when used with normal (filtered) audio input, use flat and preemphasis modems | |||
| { | |||
| demodState[0].prefilter = PREFILTER_PREEMPHASIS; | |||
| demodState[0].bpf.coeffs = (int16_t*)bpf1200; | |||
| demodState[0].bpf.taps = sizeof(bpf1200) / sizeof(*bpf1200); | |||
| demodState[0].bpf.gainShift = 15; | |||
| } | |||
| if(ModemConfig.modem == MODEM_1200) //Bell 202 | |||
| { | |||
| markFreq = 1200.f; | |||
| spaceFreq = 2200.f; | |||
| } | |||
| else //V.23 | |||
| { | |||
| markFreq = 1300.f; | |||
| spaceFreq = 2100.f; | |||
| } | |||
| } | |||
| else if(ModemConfig.modem == MODEM_300) | |||
| { | |||
| demodCount = 1; | |||
| N = N300; | |||
| baudRate = 300.f; | |||
| markFreq = 1600.f; | |||
| spaceFreq = 1800.f; | |||
| demodState[0].pllStep = PLL300_STEP; | |||
| demodState[0].pllLockedTune = PLL300_LOCKED_TUNE * (float)((uint32_t)1 << PLL_TUNE_BITS); | |||
| demodState[0].pllNotLockedTune = PLL300_NOT_LOCKED_TUNE * (float)((uint32_t)1 << PLL_TUNE_BITS); | |||
| demodState[0].dcdMax = DCD300_MAXPULSE; | |||
| demodState[0].dcdThres = DCD300_THRES; | |||
| demodState[0].dcdInc = DCD300_INC; | |||
| demodState[0].dcdDec = DCD300_DEC; | |||
| demodState[0].dcdTune = DCD300_TUNE * (float)((uint32_t)1 << PLL_TUNE_BITS); | |||
| demodState[0].prefilter = PREFILTER_FLAT; | |||
| demodState[0].bpf.coeffs = (int16_t*)bpf300; | |||
| demodState[0].bpf.taps = sizeof(bpf300) / sizeof(*bpf300); | |||
| demodState[0].bpf.gainShift = 16; | |||
| demodState[0].lpf.coeffs = (int16_t*)lpf300; | |||
| demodState[0].lpf.taps = sizeof(lpf300) / sizeof(*lpf300); | |||
| demodState[0].lpf.gainShift = 15; | |||
| } | |||
| else if(ModemConfig.modem == MODEM_9600) | |||
| { | |||
| demodCount = 1; | |||
| N = N9600; | |||
| baudRate = 9600.f; | |||
| markFreq = 38400.f / (float)DAC_SINE_SIZE; //use as DAC sample rate | |||
| demodState[0].pllStep = PLL9600_STEP; | |||
| demodState[0].pllLockedTune = PLL9600_LOCKED_TUNE * (float)((uint32_t)1 << PLL_TUNE_BITS); | |||
| demodState[0].pllNotLockedTune = PLL9600_NOT_LOCKED_TUNE * (float)((uint32_t)1 << PLL_TUNE_BITS); | |||
| demodState[0].dcdMax = DCD9600_MAXPULSE; | |||
| demodState[0].dcdThres = DCD9600_THRES; | |||
| demodState[0].dcdInc = DCD9600_INC; | |||
| demodState[0].dcdDec = DCD9600_DEC; | |||
| demodState[0].dcdTune = DCD9600_TUNE * (float)((uint32_t)1 << PLL_TUNE_BITS); | |||
| demodState[0].prefilter = PREFILTER_NONE; | |||
| //this filter will be used for RX and TX | |||
| demodState[0].lpf.coeffs = (int16_t*)lpf9600; | |||
| demodState[0].lpf.taps = sizeof(lpf9600) / sizeof(*lpf9600); | |||
| demodState[0].lpf.gainShift = 16; | |||
| } | |||
| MODEM_LL_ADC_SET_SAMPLE_RATE(baudRate * N * MODEM_LL_OVERSAMPLING_FACTOR); | |||
| MODEM_LL_ADC_TIMER_ENABLE(); | |||
| markStep = MODEM_LL_DAC_TIMER_CALCULATE_STEP(DAC_SINE_SIZE * markFreq); | |||
| spaceStep = MODEM_LL_DAC_TIMER_CALCULATE_STEP(DAC_SINE_SIZE * spaceFreq); | |||
| baudRateStep = MODEM_LL_BAUDRATE_TIMER_CALCULATE_STEP(baudRate); | |||
| MODEM_LL_BAUDRATE_TIMER_SET_RELOAD_VALUE(baudRateStep); | |||
| for(uint8_t i = 0; i < N; i++) //calculate correlator coefficients | |||
| { | |||
| coeffLoI[i] = 4095.f * cosf(2.f * 3.1416f * (float)i / (float)N * markFreq / baudRate); | |||
| coeffLoQ[i] = 4095.f * sinf(2.f * 3.1416f * (float)i / (float)N * markFreq / baudRate); | |||
| coeffHiI[i] = 4095.f * cosf(2.f * 3.1416f * (float)i / (float)N * spaceFreq / baudRate); | |||
| coeffHiQ[i] = 4095.f * sinf(2.f * 3.1416f * (float)i / (float)N * spaceFreq / baudRate); | |||
| } | |||
| for(uint8_t i = 0; i < DAC_SINE_SIZE; i++) //calculate DAC sine samples | |||
| { | |||
| if(ModemConfig.usePWM) | |||
| //produce values in range 1 to 256 | |||
| dacSine[i] = ((sinf(2.f * 3.1416f * (float)i / (float)DAC_SINE_SIZE) + 1.f) * 128.f); | |||
| else | |||
| dacSine[i] = ((7.f * sinf(2.f * 3.1416f * (float)i / (float)DAC_SINE_SIZE)) + 8.f); | |||
| } | |||
| if(ModemConfig.usePWM) | |||
| { | |||
| MODEM_LL_PWM_INITIALIZE(); | |||
| } | |||
| } | |||
| @ -0,0 +1,176 @@ | |||
| /** | |||
| ****************************************************************************** | |||
| * @file syscalls.c | |||
| * @author Auto-generated by STM32CubeIDE | |||
| * @brief STM32CubeIDE Minimal System calls file | |||
| * | |||
| * For more information about which c-functions | |||
| * need which of these lowlevel functions | |||
| * please consult the Newlib libc-manual | |||
| ****************************************************************************** | |||
| * @attention | |||
| * | |||
| * Copyright (c) 2020-2023 STMicroelectronics. | |||
| * All rights reserved. | |||
| * | |||
| * This software is licensed under terms that can be found in the LICENSE file | |||
| * in the root directory of this software component. | |||
| * If no LICENSE file comes with this software, it is provided AS-IS. | |||
| * | |||
| ****************************************************************************** | |||
| */ | |||
| /* Includes */ | |||
| #include <sys/stat.h> | |||
| #include <stdlib.h> | |||
| #include <errno.h> | |||
| #include <stdio.h> | |||
| #include <signal.h> | |||
| #include <time.h> | |||
| #include <sys/time.h> | |||
| #include <sys/times.h> | |||
| /* Variables */ | |||
| extern int __io_putchar(int ch) __attribute__((weak)); | |||
| extern int __io_getchar(void) __attribute__((weak)); | |||
| char *__env[1] = { 0 }; | |||
| char **environ = __env; | |||
| /* Functions */ | |||
| void initialise_monitor_handles() | |||
| { | |||
| } | |||
| int _getpid(void) | |||
| { | |||
| return 1; | |||
| } | |||
| int _kill(int pid, int sig) | |||
| { | |||
| (void)pid; | |||
| (void)sig; | |||
| errno = EINVAL; | |||
| return -1; | |||
| } | |||
| void _exit (int status) | |||
| { | |||
| _kill(status, -1); | |||
| while (1) {} /* Make sure we hang here */ | |||
| } | |||
| __attribute__((weak)) int _read(int file, char *ptr, int len) | |||
| { | |||
| (void)file; | |||
| int DataIdx; | |||
| for (DataIdx = 0; DataIdx < len; DataIdx++) | |||
| { | |||
| *ptr++ = __io_getchar(); | |||
| } | |||
| return len; | |||
| } | |||
| __attribute__((weak)) int _write(int file, char *ptr, int len) | |||
| { | |||
| (void)file; | |||
| int DataIdx; | |||
| for (DataIdx = 0; DataIdx < len; DataIdx++) | |||
| { | |||
| __io_putchar(*ptr++); | |||
| } | |||
| return len; | |||
| } | |||
| int _close(int file) | |||
| { | |||
| (void)file; | |||
| return -1; | |||
| } | |||
| int _fstat(int file, struct stat *st) | |||
| { | |||
| (void)file; | |||
| st->st_mode = S_IFCHR; | |||
| return 0; | |||
| } | |||
| int _isatty(int file) | |||
| { | |||
| (void)file; | |||
| return 1; | |||
| } | |||
| int _lseek(int file, int ptr, int dir) | |||
| { | |||
| (void)file; | |||
| (void)ptr; | |||
| (void)dir; | |||
| return 0; | |||
| } | |||
| int _open(char *path, int flags, ...) | |||
| { | |||
| (void)path; | |||
| (void)flags; | |||
| /* Pretend like we always fail */ | |||
| return -1; | |||
| } | |||
| int _wait(int *status) | |||
| { | |||
| (void)status; | |||
| errno = ECHILD; | |||
| return -1; | |||
| } | |||
| int _unlink(char *name) | |||
| { | |||
| (void)name; | |||
| errno = ENOENT; | |||
| return -1; | |||
| } | |||
| int _times(struct tms *buf) | |||
| { | |||
| (void)buf; | |||
| return -1; | |||
| } | |||
| int _stat(char *file, struct stat *st) | |||
| { | |||
| (void)file; | |||
| st->st_mode = S_IFCHR; | |||
| return 0; | |||
| } | |||
| int _link(char *old, char *new) | |||
| { | |||
| (void)old; | |||
| (void)new; | |||
| errno = EMLINK; | |||
| return -1; | |||
| } | |||
| int _fork(void) | |||
| { | |||
| errno = EAGAIN; | |||
| return -1; | |||
| } | |||
| int _execve(char *name, char **argv, char **env) | |||
| { | |||
| (void)name; | |||
| (void)argv; | |||
| (void)env; | |||
| errno = ENOMEM; | |||
| return -1; | |||
| } | |||
| @ -0,0 +1,79 @@ | |||
| /** | |||
| ****************************************************************************** | |||
| * @file sysmem.c | |||
| * @author Generated by STM32CubeIDE | |||
| * @brief STM32CubeIDE System Memory calls file | |||
| * | |||
| * For more information about which C functions | |||
| * need which of these lowlevel functions | |||
| * please consult the newlib libc manual | |||
| ****************************************************************************** | |||
| * @attention | |||
| * | |||
| * Copyright (c) 2023 STMicroelectronics. | |||
| * All rights reserved. | |||
| * | |||
| * This software is licensed under terms that can be found in the LICENSE file | |||
| * in the root directory of this software component. | |||
| * If no LICENSE file comes with this software, it is provided AS-IS. | |||
| * | |||
| ****************************************************************************** | |||
| */ | |||
| /* Includes */ | |||
| #include <errno.h> | |||
| #include <stdint.h> | |||
| /** | |||
| * Pointer to the current high watermark of the heap usage | |||
| */ | |||
| static uint8_t *__sbrk_heap_end = NULL; | |||
| /** | |||
| * @brief _sbrk() allocates memory to the newlib heap and is used by malloc | |||
| * and others from the C library | |||
| * | |||
| * @verbatim | |||
| * ############################################################################ | |||
| * # .data # .bss # newlib heap # MSP stack # | |||
| * # # # # Reserved by _Min_Stack_Size # | |||
| * ############################################################################ | |||
| * ^-- RAM start ^-- _end _estack, RAM end --^ | |||
| * @endverbatim | |||
| * | |||
| * This implementation starts allocating at the '_end' linker symbol | |||
| * The '_Min_Stack_Size' linker symbol reserves a memory for the MSP stack | |||
| * The implementation considers '_estack' linker symbol to be RAM end | |||
| * NOTE: If the MSP stack, at any point during execution, grows larger than the | |||
| * reserved size, please increase the '_Min_Stack_Size'. | |||
| * | |||
| * @param incr Memory size | |||
| * @return Pointer to allocated memory | |||
| */ | |||
| void *_sbrk(ptrdiff_t incr) | |||
| { | |||
| extern uint8_t _end; /* Symbol defined in the linker script */ | |||
| extern uint8_t _estack; /* Symbol defined in the linker script */ | |||
| extern uint32_t _Min_Stack_Size; /* Symbol defined in the linker script */ | |||
| const uint32_t stack_limit = (uint32_t)&_estack - (uint32_t)&_Min_Stack_Size; | |||
| const uint8_t *max_heap = (uint8_t *)stack_limit; | |||
| uint8_t *prev_heap_end; | |||
| /* Initialize heap end at first call */ | |||
| if (NULL == __sbrk_heap_end) | |||
| { | |||
| __sbrk_heap_end = &_end; | |||
| } | |||
| /* Protect heap from growing into the reserved MSP stack */ | |||
| if (__sbrk_heap_end + incr > max_heap) | |||
| { | |||
| errno = ENOMEM; | |||
| return (void *)-1; | |||
| } | |||
| prev_heap_end = __sbrk_heap_end; | |||
| __sbrk_heap_end += incr; | |||
| return (void *)prev_heap_end; | |||
| } | |||
| @ -0,0 +1,224 @@ | |||
| /* | |||
| Copyright 2020-2023 Piotr Wilkon | |||
| This file is part of VP-Digi. | |||
| VP-Digi 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. | |||
| VP-Digi 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 VP-Digi. If not, see <http://www.gnu.org/licenses/>. | |||
| */ | |||
| #include "terminal.h" | |||
| #include "ax25.h" | |||
| #include "common.h" | |||
| #include <string.h> | |||
| #include <systick.h> | |||
| #include <uart.h> | |||
| #include "digipeater.h" | |||
| #include "kiss.h" | |||
| Uart Uart1 = {.defaultMode = MODE_KISS}, Uart2 = {.defaultMode = MODE_KISS}, UartUsb= {.defaultMode = MODE_KISS}; | |||
| static void handleInterrupt(Uart *port) | |||
| { | |||
| if(UART_LL_CHECK_RX_NOT_EMPTY(port->port)) //byte received | |||
| { | |||
| UART_LL_CLEAR_RX_NOT_EMPTY(port->port); | |||
| uint8_t data = port->port->DR; | |||
| port->rxBuffer[port->rxBufferHead++] = data; //store it | |||
| port->rxBufferHead %= UART_BUFFER_SIZE; | |||
| KissParse(port, data); | |||
| TermHandleSpecial(port); | |||
| } | |||
| if(UART_LL_CHECK_RX_IDLE(port->port)) //line is idle, end of data reception | |||
| { | |||
| UART_LL_GET_DATA(port->port); //reset idle flag by dummy read | |||
| if(port->rxBufferHead != 0) | |||
| { | |||
| if(((port->rxBuffer[port->rxBufferHead - 1] == '\r') || (port->rxBuffer[port->rxBufferHead - 1] == '\n'))) //data ends with \r or \n, process as data | |||
| { | |||
| port->rxType = DATA_TERM; | |||
| } | |||
| } | |||
| } | |||
| if(UART_LL_CHECK_TX_EMPTY(port->port)) //TX buffer empty | |||
| { | |||
| if((port->txBufferHead != port->txBufferTail) || port->txBufferFull) //if there is anything to transmit | |||
| { | |||
| UART_LL_PUT_DATA(port->port, port->txBuffer[port->txBufferTail++]); | |||
| port->txBufferTail %= UART_BUFFER_SIZE; | |||
| port->txBufferFull = 0; | |||
| } | |||
| else //nothing more to be transmitted | |||
| { | |||
| UART_LL_DISABLE_TX_EMPTY_INTERRUPT(port->port); | |||
| } | |||
| } | |||
| } | |||
| void UART_LL_UART1_INTERUPT_HANDLER(void) __attribute__ ((interrupt)); | |||
| void UART_LL_UART1_INTERUPT_HANDLER(void) | |||
| { | |||
| handleInterrupt(&Uart1); | |||
| } | |||
| void UART_LL_UART2_INTERUPT_HANDLER(void) __attribute__ ((interrupt)); | |||
| void UART_LL_UART2_INTERUPT_HANDLER(void) | |||
| { | |||
| handleInterrupt(&Uart2); | |||
| } | |||
| void UartSendByte(Uart *port, uint8_t data) | |||
| { | |||
| if(!port->enabled) | |||
| return; | |||
| if(port->isUsb) | |||
| { | |||
| CDC_Transmit_FS(&data, 1); | |||
| } | |||
| else | |||
| { | |||
| while(port->txBufferFull) | |||
| ; | |||
| port->txBuffer[port->txBufferHead++] = data; | |||
| port->txBufferHead %= UART_BUFFER_SIZE; | |||
| __disable_irq(); | |||
| if(port->txBufferHead == port->txBufferTail) | |||
| port->txBufferFull = 1; | |||
| if(0 == (UART_LL_CHECK_ENABLED_TX_EMPTY_INTERRUPT(port->port))) | |||
| UART_LL_ENABLE_TX_EMPTY_INTERRUPT(port->port); | |||
| __enable_irq(); | |||
| } | |||
| } | |||
| void UartSendString(Uart *port, void *data, uint16_t len) | |||
| { | |||
| if(0 == len) | |||
| len = strlen((char*)data); | |||
| for(uint16_t i = 0; i < len; i++) | |||
| { | |||
| UartSendByte(port, ((uint8_t*)data)[i]); | |||
| } | |||
| } | |||
| static unsigned int findHighestPosition(unsigned int n) | |||
| { | |||
| unsigned int i = 1; | |||
| while((i * 10) <= n) | |||
| i *= 10; | |||
| return i; | |||
| } | |||
| void UartSendNumber(Uart *port, int32_t n) | |||
| { | |||
| if(n < 0) | |||
| UartSendByte(port, '-'); | |||
| n = abs(n); | |||
| unsigned int position = findHighestPosition(n); | |||
| while(position) | |||
| { | |||
| unsigned int number = n / position; | |||
| UartSendByte(port, (number + 48)); | |||
| n -= (number * position); | |||
| position /= 10; | |||
| } | |||
| } | |||
| void UartInit(Uart *port, USART_TypeDef *uart, uint32_t baud) | |||
| { | |||
| port->port = uart; | |||
| port->baudrate = baud; | |||
| port->rxType = DATA_NOTHING; | |||
| port->rxBufferHead = 0; | |||
| port->txBufferHead = 0; | |||
| port->txBufferTail = 0; | |||
| port->txBufferFull = 0; | |||
| if(port->defaultMode > MODE_MONITOR) | |||
| port->defaultMode = MODE_KISS; | |||
| port->mode = port->defaultMode; | |||
| port->enabled = 0; | |||
| port->kissBufferHead = 0; | |||
| port->lastRxBufferHead = 0; | |||
| memset((void*)port->rxBuffer, 0, sizeof(port->rxBuffer)); | |||
| memset((void*)port->txBuffer, 0, sizeof(port->txBuffer)); | |||
| memset((void*)port->kissBuffer, 0, sizeof(port->kissBuffer)); | |||
| } | |||
| void UartConfig(Uart *port, uint8_t state) | |||
| { | |||
| if(port->port == UART_LL_UART1_STRUCTURE) | |||
| { | |||
| UART_LL_UART1_INITIALIZE_PERIPHERAL(port->baudrate); | |||
| if(state) | |||
| { | |||
| UART_LL_ENABLE(port->port); | |||
| } | |||
| else | |||
| { | |||
| UART_LL_DISABLE(port->port); | |||
| } | |||
| NVIC_SetPriority(UART_LL_UART1_IRQ, 2); | |||
| if(state) | |||
| NVIC_EnableIRQ(UART_LL_UART1_IRQ); | |||
| else | |||
| NVIC_DisableIRQ(UART_LL_UART1_IRQ); | |||
| port->enabled = state > 0; | |||
| port->isUsb = 0; | |||
| } | |||
| else if(port->port == UART_LL_UART2_STRUCTURE) | |||
| { | |||
| UART_LL_UART2_INITIALIZE_PERIPHERAL(port->baudrate); | |||
| if(state) | |||
| { | |||
| UART_LL_ENABLE(port->port); | |||
| } | |||
| else | |||
| { | |||
| UART_LL_DISABLE(port->port); | |||
| } | |||
| NVIC_SetPriority(UART_LL_UART2_IRQ, 2); | |||
| if(state) | |||
| NVIC_EnableIRQ(UART_LL_UART2_IRQ); | |||
| else | |||
| NVIC_DisableIRQ(UART_LL_UART2_IRQ); | |||
| port->enabled = state > 0; | |||
| port->isUsb = 0; | |||
| } | |||
| else | |||
| { | |||
| port->isUsb = 1; | |||
| port->enabled = state > 0; | |||
| } | |||
| } | |||
| void UartClearRx(Uart *port) | |||
| { | |||
| port->rxBufferHead = 0; | |||
| port->rxType = DATA_NOTHING; | |||
| } | |||
| @ -0,0 +1,6 @@ | |||
| This software component is provided to you as part of a software package and | |||
| applicable license terms are in the Package_license file. If you received this | |||
| software component outside of a package or without applicable license terms, | |||
| the terms of the Apache-2.0 license shall apply. | |||
| You may obtain a copy of the Apache-2.0 at: | |||
| https://opensource.org/licenses/Apache-2.0 | |||
| @ -0,0 +1,201 @@ | |||
| Apache License | |||
| Version 2.0, January 2004 | |||
| http://www.apache.org/licenses/ | |||
| TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION | |||
| 1. Definitions. | |||
| "License" shall mean the terms and conditions for use, reproduction, | |||
| and distribution as defined by Sections 1 through 9 of this document. | |||
| "Licensor" shall mean the copyright owner or entity authorized by | |||
| the copyright owner that is granting the License. | |||
| "Legal Entity" shall mean the union of the acting entity and all | |||
| other entities that control, are controlled by, or are under common | |||
| control with that entity. For the purposes of this definition, | |||
| "control" means (i) the power, direct or indirect, to cause the | |||
| direction or management of such entity, whether by contract or | |||
| otherwise, or (ii) ownership of fifty percent (50%) or more of the | |||
| outstanding shares, or (iii) beneficial ownership of such entity. | |||
| "You" (or "Your") shall mean an individual or Legal Entity | |||
| exercising permissions granted by this License. | |||
| "Source" form shall mean the preferred form for making modifications, | |||
| including but not limited to software source code, documentation | |||
| source, and configuration files. | |||
| "Object" form shall mean any form resulting from mechanical | |||
| transformation or translation of a Source form, including but | |||
| not limited to compiled object code, generated documentation, | |||
| and conversions to other media types. | |||
| "Work" shall mean the work of authorship, whether in Source or | |||
| Object form, made available under the License, as indicated by a | |||
| copyright notice that is included in or attached to the work | |||
| (an example is provided in the Appendix below). | |||
| "Derivative Works" shall mean any work, whether in Source or Object | |||
| form, that is based on (or derived from) the Work and for which the | |||
| editorial revisions, annotations, elaborations, or other modifications | |||
| represent, as a whole, an original work of authorship. For the purposes | |||
| of this License, Derivative Works shall not include works that remain | |||
| separable from, or merely link (or bind by name) to the interfaces of, | |||
| the Work and Derivative Works thereof. | |||
| "Contribution" shall mean any work of authorship, including | |||
| the original version of the Work and any modifications or additions | |||
| to that Work or Derivative Works thereof, that is intentionally | |||
| submitted to Licensor for inclusion in the Work by the copyright owner | |||
| or by an individual or Legal Entity authorized to submit on behalf of | |||
| the copyright owner. For the purposes of this definition, "submitted" | |||
| means any form of electronic, verbal, or written communication sent | |||
| to the Licensor or its representatives, including but not limited to | |||
| communication on electronic mailing lists, source code control systems, | |||
| and issue tracking systems that are managed by, or on behalf of, the | |||
| Licensor for the purpose of discussing and improving the Work, but | |||
| excluding communication that is conspicuously marked or otherwise | |||
| designated in writing by the copyright owner as "Not a Contribution." | |||
| "Contributor" shall mean Licensor and any individual or Legal Entity | |||
| on behalf of whom a Contribution has been received by Licensor and | |||
| subsequently incorporated within the Work. | |||
| 2. Grant of Copyright License. Subject to the terms and conditions of | |||
| this License, each Contributor hereby grants to You a perpetual, | |||
| worldwide, non-exclusive, no-charge, royalty-free, irrevocable | |||
| copyright license to reproduce, prepare Derivative Works of, | |||
| publicly display, publicly perform, sublicense, and distribute the | |||
| Work and such Derivative Works in Source or Object form. | |||
| 3. Grant of Patent License. Subject to the terms and conditions of | |||
| this License, each Contributor hereby grants to You a perpetual, | |||
| worldwide, non-exclusive, no-charge, royalty-free, irrevocable | |||
| (except as stated in this section) patent license to make, have made, | |||
| use, offer to sell, sell, import, and otherwise transfer the Work, | |||
| where such license applies only to those patent claims licensable | |||
| by such Contributor that are necessarily infringed by their | |||
| Contribution(s) alone or by combination of their Contribution(s) | |||
| with the Work to which such Contribution(s) was submitted. If You | |||
| institute patent litigation against any entity (including a | |||
| cross-claim or counterclaim in a lawsuit) alleging that the Work | |||
| or a Contribution incorporated within the Work constitutes direct | |||
| or contributory patent infringement, then any patent licenses | |||
| granted to You under this License for that Work shall terminate | |||
| as of the date such litigation is filed. | |||
| 4. Redistribution. You may reproduce and distribute copies of the | |||
| Work or Derivative Works thereof in any medium, with or without | |||
| modifications, and in Source or Object form, provided that You | |||
| meet the following conditions: | |||
| (a) You must give any other recipients of the Work or | |||
| Derivative Works a copy of this License; and | |||
| (b) You must cause any modified files to carry prominent notices | |||
| stating that You changed the files; and | |||
| (c) You must retain, in the Source form of any Derivative Works | |||
| that You distribute, all copyright, patent, trademark, and | |||
| attribution notices from the Source form of the Work, | |||
| excluding those notices that do not pertain to any part of | |||
| the Derivative Works; and | |||
| (d) If the Work includes a "NOTICE" text file as part of its | |||
| distribution, then any Derivative Works that You distribute must | |||
| include a readable copy of the attribution notices contained | |||
| within such NOTICE file, excluding those notices that do not | |||
| pertain to any part of the Derivative Works, in at least one | |||
| of the following places: within a NOTICE text file distributed | |||
| as part of the Derivative Works; within the Source form or | |||
| documentation, if provided along with the Derivative Works; or, | |||
| within a display generated by the Derivative Works, if and | |||
| wherever such third-party notices normally appear. The contents | |||
| of the NOTICE file are for informational purposes only and | |||
| do not modify the License. You may add Your own attribution | |||
| notices within Derivative Works that You distribute, alongside | |||
| or as an addendum to the NOTICE text from the Work, provided | |||
| that such additional attribution notices cannot be construed | |||
| as modifying the License. | |||
| You may add Your own copyright statement to Your modifications and | |||
| may provide additional or different license terms and conditions | |||
| for use, reproduction, or distribution of Your modifications, or | |||
| for any such Derivative Works as a whole, provided Your use, | |||
| reproduction, and distribution of the Work otherwise complies with | |||
| the conditions stated in this License. | |||
| 5. Submission of Contributions. Unless You explicitly state otherwise, | |||
| any Contribution intentionally submitted for inclusion in the Work | |||
| by You to the Licensor shall be under the terms and conditions of | |||
| this License, without any additional terms or conditions. | |||
| Notwithstanding the above, nothing herein shall supersede or modify | |||
| the terms of any separate license agreement you may have executed | |||
| with Licensor regarding such Contributions. | |||
| 6. Trademarks. This License does not grant permission to use the trade | |||
| names, trademarks, service marks, or product names of the Licensor, | |||
| except as required for reasonable and customary use in describing the | |||
| origin of the Work and reproducing the content of the NOTICE file. | |||
| 7. Disclaimer of Warranty. Unless required by applicable law or | |||
| agreed to in writing, Licensor provides the Work (and each | |||
| Contributor provides its Contributions) on an "AS IS" BASIS, | |||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or | |||
| implied, including, without limitation, any warranties or conditions | |||
| of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A | |||
| PARTICULAR PURPOSE. You are solely responsible for determining the | |||
| appropriateness of using or redistributing the Work and assume any | |||
| risks associated with Your exercise of permissions under this License. | |||
| 8. Limitation of Liability. In no event and under no legal theory, | |||
| whether in tort (including negligence), contract, or otherwise, | |||
| unless required by applicable law (such as deliberate and grossly | |||
| negligent acts) or agreed to in writing, shall any Contributor be | |||
| liable to You for damages, including any direct, indirect, special, | |||
| incidental, or consequential damages of any character arising as a | |||
| result of this License or out of the use or inability to use the | |||
| Work (including but not limited to damages for loss of goodwill, | |||
| work stoppage, computer failure or malfunction, or any and all | |||
| other commercial damages or losses), even if such Contributor | |||
| has been advised of the possibility of such damages. | |||
| 9. Accepting Warranty or Additional Liability. While redistributing | |||
| the Work or Derivative Works thereof, You may choose to offer, | |||
| and charge a fee for, acceptance of support, warranty, indemnity, | |||
| or other liability obligations and/or rights consistent with this | |||
| License. However, in accepting such obligations, You may act only | |||
| on Your own behalf and on Your sole responsibility, not on behalf | |||
| of any other Contributor, and only if You agree to indemnify, | |||
| defend, and hold each Contributor harmless for any liability | |||
| incurred by, or claims asserted against, such Contributor by reason | |||
| of your accepting any such warranty or additional liability. | |||
| END OF TERMS AND CONDITIONS | |||
| APPENDIX: How to apply the Apache License to your work. | |||
| To apply the Apache License to your work, attach the following | |||
| boilerplate notice, with the fields enclosed by brackets "{}" | |||
| replaced with your own identifying information. (Don't include | |||
| the brackets!) The text should be enclosed in the appropriate | |||
| comment syntax for the file format. We also recommend that a | |||
| file or class name and description of purpose be included on the | |||
| same "printed page" as the copyright notice for easier | |||
| identification within third-party archives. | |||
| Copyright {yyyy} {name of copyright owner} | |||
| Licensed under the Apache License, Version 2.0 (the "License"); | |||
| you may not use this file except in compliance with the License. | |||
| You may obtain a copy of the License at | |||
| http://www.apache.org/licenses/LICENSE-2.0 | |||
| Unless required by applicable law or agreed to in writing, software | |||
| distributed under the License is distributed on an "AS IS" BASIS, | |||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
| See the License for the specific language governing permissions and | |||
| limitations under the License. | |||
| @ -0,0 +1,638 @@ | |||
| /** | |||
| ****************************************************************************** | |||
| * @file stm32f1xx_ll_cortex.h | |||
| * @author MCD Application Team | |||
| * @brief Header file of CORTEX LL module. | |||
| @verbatim | |||
| ============================================================================== | |||
| ##### How to use this driver ##### | |||
| ============================================================================== | |||
| [..] | |||
| The LL CORTEX driver contains a set of generic APIs that can be | |||
| used by user: | |||
| (+) SYSTICK configuration used by LL_mDelay and LL_Init1msTick | |||
| functions | |||
| (+) Low power mode configuration (SCB register of Cortex-MCU) | |||
| (+) MPU API to configure and enable regions | |||
| (MPU services provided only on some devices) | |||
| (+) API to access to MCU info (CPUID register) | |||
| (+) API to enable fault handler (SHCSR accesses) | |||
| @endverbatim | |||
| ****************************************************************************** | |||
| * @attention | |||
| * | |||
| * Copyright (c) 2017 STMicroelectronics. | |||
| * All rights reserved. | |||
| * | |||
| * This software is licensed under terms that can be found in the LICENSE file in | |||
| * the root directory of this software component. | |||
| * If no LICENSE file comes with this software, it is provided AS-IS. | |||
| * | |||
| ****************************************************************************** | |||
| */ | |||
| /* Define to prevent recursive inclusion -------------------------------------*/ | |||
| #ifndef __STM32F1xx_LL_CORTEX_H | |||
| #define __STM32F1xx_LL_CORTEX_H | |||
| #ifdef __cplusplus | |||
| extern "C" { | |||
| #endif | |||
| /* Includes ------------------------------------------------------------------*/ | |||
| #include "stm32f1xx.h" | |||
| /** @addtogroup STM32F1xx_LL_Driver | |||
| * @{ | |||
| */ | |||
| /** @defgroup CORTEX_LL CORTEX | |||
| * @{ | |||
| */ | |||
| /* Private types -------------------------------------------------------------*/ | |||
| /* Private variables ---------------------------------------------------------*/ | |||
| /* Private constants ---------------------------------------------------------*/ | |||
| /* Private macros ------------------------------------------------------------*/ | |||
| /* Exported types ------------------------------------------------------------*/ | |||
| /* Exported constants --------------------------------------------------------*/ | |||
| /** @defgroup CORTEX_LL_Exported_Constants CORTEX Exported Constants | |||
| * @{ | |||
| */ | |||
| /** @defgroup CORTEX_LL_EC_CLKSOURCE_HCLK SYSTICK Clock Source | |||
| * @{ | |||
| */ | |||
| #define LL_SYSTICK_CLKSOURCE_HCLK_DIV8 0x00000000U /*!< AHB clock divided by 8 selected as SysTick clock source.*/ | |||
| #define LL_SYSTICK_CLKSOURCE_HCLK SysTick_CTRL_CLKSOURCE_Msk /*!< AHB clock selected as SysTick clock source. */ | |||
| /** | |||
| * @} | |||
| */ | |||
| /** @defgroup CORTEX_LL_EC_FAULT Handler Fault type | |||
| * @{ | |||
| */ | |||
| #define LL_HANDLER_FAULT_USG SCB_SHCSR_USGFAULTENA_Msk /*!< Usage fault */ | |||
| #define LL_HANDLER_FAULT_BUS SCB_SHCSR_BUSFAULTENA_Msk /*!< Bus fault */ | |||
| #define LL_HANDLER_FAULT_MEM SCB_SHCSR_MEMFAULTENA_Msk /*!< Memory management fault */ | |||
| /** | |||
| * @} | |||
| */ | |||
| #if __MPU_PRESENT | |||
| /** @defgroup CORTEX_LL_EC_CTRL_HFNMI_PRIVDEF MPU Control | |||
| * @{ | |||
| */ | |||
| #define LL_MPU_CTRL_HFNMI_PRIVDEF_NONE 0x00000000U /*!< Disable NMI and privileged SW access */ | |||
| #define LL_MPU_CTRL_HARDFAULT_NMI MPU_CTRL_HFNMIENA_Msk /*!< Enables the operation of MPU during hard fault, NMI, and FAULTMASK handlers */ | |||
| #define LL_MPU_CTRL_PRIVILEGED_DEFAULT MPU_CTRL_PRIVDEFENA_Msk /*!< Enable privileged software access to default memory map */ | |||
| #define LL_MPU_CTRL_HFNMI_PRIVDEF (MPU_CTRL_HFNMIENA_Msk | MPU_CTRL_PRIVDEFENA_Msk) /*!< Enable NMI and privileged SW access */ | |||
| /** | |||
| * @} | |||
| */ | |||
| /** @defgroup CORTEX_LL_EC_REGION MPU Region Number | |||
| * @{ | |||
| */ | |||
| #define LL_MPU_REGION_NUMBER0 0x00U /*!< REGION Number 0 */ | |||
| #define LL_MPU_REGION_NUMBER1 0x01U /*!< REGION Number 1 */ | |||
| #define LL_MPU_REGION_NUMBER2 0x02U /*!< REGION Number 2 */ | |||
| #define LL_MPU_REGION_NUMBER3 0x03U /*!< REGION Number 3 */ | |||
| #define LL_MPU_REGION_NUMBER4 0x04U /*!< REGION Number 4 */ | |||
| #define LL_MPU_REGION_NUMBER5 0x05U /*!< REGION Number 5 */ | |||
| #define LL_MPU_REGION_NUMBER6 0x06U /*!< REGION Number 6 */ | |||
| #define LL_MPU_REGION_NUMBER7 0x07U /*!< REGION Number 7 */ | |||
| /** | |||
| * @} | |||
| */ | |||
| /** @defgroup CORTEX_LL_EC_REGION_SIZE MPU Region Size | |||
| * @{ | |||
| */ | |||
| #define LL_MPU_REGION_SIZE_32B (0x04U << MPU_RASR_SIZE_Pos) /*!< 32B Size of the MPU protection region */ | |||
| #define LL_MPU_REGION_SIZE_64B (0x05U << MPU_RASR_SIZE_Pos) /*!< 64B Size of the MPU protection region */ | |||
| #define LL_MPU_REGION_SIZE_128B (0x06U << MPU_RASR_SIZE_Pos) /*!< 128B Size of the MPU protection region */ | |||
| #define LL_MPU_REGION_SIZE_256B (0x07U << MPU_RASR_SIZE_Pos) /*!< 256B Size of the MPU protection region */ | |||
| #define LL_MPU_REGION_SIZE_512B (0x08U << MPU_RASR_SIZE_Pos) /*!< 512B Size of the MPU protection region */ | |||
| #define LL_MPU_REGION_SIZE_1KB (0x09U << MPU_RASR_SIZE_Pos) /*!< 1KB Size of the MPU protection region */ | |||
| #define LL_MPU_REGION_SIZE_2KB (0x0AU << MPU_RASR_SIZE_Pos) /*!< 2KB Size of the MPU protection region */ | |||
| #define LL_MPU_REGION_SIZE_4KB (0x0BU << MPU_RASR_SIZE_Pos) /*!< 4KB Size of the MPU protection region */ | |||
| #define LL_MPU_REGION_SIZE_8KB (0x0CU << MPU_RASR_SIZE_Pos) /*!< 8KB Size of the MPU protection region */ | |||
| #define LL_MPU_REGION_SIZE_16KB (0x0DU << MPU_RASR_SIZE_Pos) /*!< 16KB Size of the MPU protection region */ | |||
| #define LL_MPU_REGION_SIZE_32KB (0x0EU << MPU_RASR_SIZE_Pos) /*!< 32KB Size of the MPU protection region */ | |||
| #define LL_MPU_REGION_SIZE_64KB (0x0FU << MPU_RASR_SIZE_Pos) /*!< 64KB Size of the MPU protection region */ | |||
| #define LL_MPU_REGION_SIZE_128KB (0x10U << MPU_RASR_SIZE_Pos) /*!< 128KB Size of the MPU protection region */ | |||
| #define LL_MPU_REGION_SIZE_256KB (0x11U << MPU_RASR_SIZE_Pos) /*!< 256KB Size of the MPU protection region */ | |||
| #define LL_MPU_REGION_SIZE_512KB (0x12U << MPU_RASR_SIZE_Pos) /*!< 512KB Size of the MPU protection region */ | |||
| #define LL_MPU_REGION_SIZE_1MB (0x13U << MPU_RASR_SIZE_Pos) /*!< 1MB Size of the MPU protection region */ | |||
| #define LL_MPU_REGION_SIZE_2MB (0x14U << MPU_RASR_SIZE_Pos) /*!< 2MB Size of the MPU protection region */ | |||
| #define LL_MPU_REGION_SIZE_4MB (0x15U << MPU_RASR_SIZE_Pos) /*!< 4MB Size of the MPU protection region */ | |||
| #define LL_MPU_REGION_SIZE_8MB (0x16U << MPU_RASR_SIZE_Pos) /*!< 8MB Size of the MPU protection region */ | |||
| #define LL_MPU_REGION_SIZE_16MB (0x17U << MPU_RASR_SIZE_Pos) /*!< 16MB Size of the MPU protection region */ | |||
| #define LL_MPU_REGION_SIZE_32MB (0x18U << MPU_RASR_SIZE_Pos) /*!< 32MB Size of the MPU protection region */ | |||
| #define LL_MPU_REGION_SIZE_64MB (0x19U << MPU_RASR_SIZE_Pos) /*!< 64MB Size of the MPU protection region */ | |||
| #define LL_MPU_REGION_SIZE_128MB (0x1AU << MPU_RASR_SIZE_Pos) /*!< 128MB Size of the MPU protection region */ | |||
| #define LL_MPU_REGION_SIZE_256MB (0x1BU << MPU_RASR_SIZE_Pos) /*!< 256MB Size of the MPU protection region */ | |||
| #define LL_MPU_REGION_SIZE_512MB (0x1CU << MPU_RASR_SIZE_Pos) /*!< 512MB Size of the MPU protection region */ | |||
| #define LL_MPU_REGION_SIZE_1GB (0x1DU << MPU_RASR_SIZE_Pos) /*!< 1GB Size of the MPU protection region */ | |||
| #define LL_MPU_REGION_SIZE_2GB (0x1EU << MPU_RASR_SIZE_Pos) /*!< 2GB Size of the MPU protection region */ | |||
| #define LL_MPU_REGION_SIZE_4GB (0x1FU << MPU_RASR_SIZE_Pos) /*!< 4GB Size of the MPU protection region */ | |||
| /** | |||
| * @} | |||
| */ | |||
| /** @defgroup CORTEX_LL_EC_REGION_PRIVILEDGES MPU Region Privileges | |||
| * @{ | |||
| */ | |||
| #define LL_MPU_REGION_NO_ACCESS (0x00U << MPU_RASR_AP_Pos) /*!< No access*/ | |||
| #define LL_MPU_REGION_PRIV_RW (0x01U << MPU_RASR_AP_Pos) /*!< RW privileged (privileged access only)*/ | |||
| #define LL_MPU_REGION_PRIV_RW_URO (0x02U << MPU_RASR_AP_Pos) /*!< RW privileged - RO user (Write in a user program generates a fault) */ | |||
| #define LL_MPU_REGION_FULL_ACCESS (0x03U << MPU_RASR_AP_Pos) /*!< RW privileged & user (Full access) */ | |||
| #define LL_MPU_REGION_PRIV_RO (0x05U << MPU_RASR_AP_Pos) /*!< RO privileged (privileged read only)*/ | |||
| #define LL_MPU_REGION_PRIV_RO_URO (0x06U << MPU_RASR_AP_Pos) /*!< RO privileged & user (read only) */ | |||
| /** | |||
| * @} | |||
| */ | |||
| /** @defgroup CORTEX_LL_EC_TEX MPU TEX Level | |||
| * @{ | |||
| */ | |||
| #define LL_MPU_TEX_LEVEL0 (0x00U << MPU_RASR_TEX_Pos) /*!< b000 for TEX bits */ | |||
| #define LL_MPU_TEX_LEVEL1 (0x01U << MPU_RASR_TEX_Pos) /*!< b001 for TEX bits */ | |||
| #define LL_MPU_TEX_LEVEL2 (0x02U << MPU_RASR_TEX_Pos) /*!< b010 for TEX bits */ | |||
| #define LL_MPU_TEX_LEVEL4 (0x04U << MPU_RASR_TEX_Pos) /*!< b100 for TEX bits */ | |||
| /** | |||
| * @} | |||
| */ | |||
| /** @defgroup CORTEX_LL_EC_INSTRUCTION_ACCESS MPU Instruction Access | |||
| * @{ | |||
| */ | |||
| #define LL_MPU_INSTRUCTION_ACCESS_ENABLE 0x00U /*!< Instruction fetches enabled */ | |||
| #define LL_MPU_INSTRUCTION_ACCESS_DISABLE MPU_RASR_XN_Msk /*!< Instruction fetches disabled*/ | |||
| /** | |||
| * @} | |||
| */ | |||
| /** @defgroup CORTEX_LL_EC_SHAREABLE_ACCESS MPU Shareable Access | |||
| * @{ | |||
| */ | |||
| #define LL_MPU_ACCESS_SHAREABLE MPU_RASR_S_Msk /*!< Shareable memory attribute */ | |||
| #define LL_MPU_ACCESS_NOT_SHAREABLE 0x00U /*!< Not Shareable memory attribute */ | |||
| /** | |||
| * @} | |||
| */ | |||
| /** @defgroup CORTEX_LL_EC_CACHEABLE_ACCESS MPU Cacheable Access | |||
| * @{ | |||
| */ | |||
| #define LL_MPU_ACCESS_CACHEABLE MPU_RASR_C_Msk /*!< Cacheable memory attribute */ | |||
| #define LL_MPU_ACCESS_NOT_CACHEABLE 0x00U /*!< Not Cacheable memory attribute */ | |||
| /** | |||
| * @} | |||
| */ | |||
| /** @defgroup CORTEX_LL_EC_BUFFERABLE_ACCESS MPU Bufferable Access | |||
| * @{ | |||
| */ | |||
| #define LL_MPU_ACCESS_BUFFERABLE MPU_RASR_B_Msk /*!< Bufferable memory attribute */ | |||
| #define LL_MPU_ACCESS_NOT_BUFFERABLE 0x00U /*!< Not Bufferable memory attribute */ | |||
| /** | |||
| * @} | |||
| */ | |||
| #endif /* __MPU_PRESENT */ | |||
| /** | |||
| * @} | |||
| */ | |||
| /* Exported macro ------------------------------------------------------------*/ | |||
| /* Exported functions --------------------------------------------------------*/ | |||
| /** @defgroup CORTEX_LL_Exported_Functions CORTEX Exported Functions | |||
| * @{ | |||
| */ | |||
| /** @defgroup CORTEX_LL_EF_SYSTICK SYSTICK | |||
| * @{ | |||
| */ | |||
| /** | |||
| * @brief This function checks if the Systick counter flag is active or not. | |||
| * @note It can be used in timeout function on application side. | |||
| * @rmtoll STK_CTRL COUNTFLAG LL_SYSTICK_IsActiveCounterFlag | |||
| * @retval State of bit (1 or 0). | |||
| */ | |||
| __STATIC_INLINE uint32_t LL_SYSTICK_IsActiveCounterFlag(void) | |||
| { | |||
| return ((SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk) == (SysTick_CTRL_COUNTFLAG_Msk)); | |||
| } | |||
| /** | |||
| * @brief Configures the SysTick clock source | |||
| * @rmtoll STK_CTRL CLKSOURCE LL_SYSTICK_SetClkSource | |||
| * @param Source This parameter can be one of the following values: | |||
| * @arg @ref LL_SYSTICK_CLKSOURCE_HCLK_DIV8 | |||
| * @arg @ref LL_SYSTICK_CLKSOURCE_HCLK | |||
| * @retval None | |||
| */ | |||
| __STATIC_INLINE void LL_SYSTICK_SetClkSource(uint32_t Source) | |||
| { | |||
| if (Source == LL_SYSTICK_CLKSOURCE_HCLK) | |||
| { | |||
| SET_BIT(SysTick->CTRL, LL_SYSTICK_CLKSOURCE_HCLK); | |||
| } | |||
| else | |||
| { | |||
| CLEAR_BIT(SysTick->CTRL, LL_SYSTICK_CLKSOURCE_HCLK); | |||
| } | |||
| } | |||
| /** | |||
| * @brief Get the SysTick clock source | |||
| * @rmtoll STK_CTRL CLKSOURCE LL_SYSTICK_GetClkSource | |||
| * @retval Returned value can be one of the following values: | |||
| * @arg @ref LL_SYSTICK_CLKSOURCE_HCLK_DIV8 | |||
| * @arg @ref LL_SYSTICK_CLKSOURCE_HCLK | |||
| */ | |||
| __STATIC_INLINE uint32_t LL_SYSTICK_GetClkSource(void) | |||
| { | |||
| return READ_BIT(SysTick->CTRL, LL_SYSTICK_CLKSOURCE_HCLK); | |||
| } | |||
| /** | |||
| * @brief Enable SysTick exception request | |||
| * @rmtoll STK_CTRL TICKINT LL_SYSTICK_EnableIT | |||
| * @retval None | |||
| */ | |||
| __STATIC_INLINE void LL_SYSTICK_EnableIT(void) | |||
| { | |||
| SET_BIT(SysTick->CTRL, SysTick_CTRL_TICKINT_Msk); | |||
| } | |||
| /** | |||
| * @brief Disable SysTick exception request | |||
| * @rmtoll STK_CTRL TICKINT LL_SYSTICK_DisableIT | |||
| * @retval None | |||
| */ | |||
| __STATIC_INLINE void LL_SYSTICK_DisableIT(void) | |||
| { | |||
| CLEAR_BIT(SysTick->CTRL, SysTick_CTRL_TICKINT_Msk); | |||
| } | |||
| /** | |||
| * @brief Checks if the SYSTICK interrupt is enabled or disabled. | |||
| * @rmtoll STK_CTRL TICKINT LL_SYSTICK_IsEnabledIT | |||
| * @retval State of bit (1 or 0). | |||
| */ | |||
| __STATIC_INLINE uint32_t LL_SYSTICK_IsEnabledIT(void) | |||
| { | |||
| return (READ_BIT(SysTick->CTRL, SysTick_CTRL_TICKINT_Msk) == (SysTick_CTRL_TICKINT_Msk)); | |||
| } | |||
| /** | |||
| * @} | |||
| */ | |||
| /** @defgroup CORTEX_LL_EF_LOW_POWER_MODE LOW POWER MODE | |||
| * @{ | |||
| */ | |||
| /** | |||
| * @brief Processor uses sleep as its low power mode | |||
| * @rmtoll SCB_SCR SLEEPDEEP LL_LPM_EnableSleep | |||
| * @retval None | |||
| */ | |||
| __STATIC_INLINE void LL_LPM_EnableSleep(void) | |||
| { | |||
| /* Clear SLEEPDEEP bit of Cortex System Control Register */ | |||
| CLEAR_BIT(SCB->SCR, ((uint32_t)SCB_SCR_SLEEPDEEP_Msk)); | |||
| } | |||
| /** | |||
| * @brief Processor uses deep sleep as its low power mode | |||
| * @rmtoll SCB_SCR SLEEPDEEP LL_LPM_EnableDeepSleep | |||
| * @retval None | |||
| */ | |||
| __STATIC_INLINE void LL_LPM_EnableDeepSleep(void) | |||
| { | |||
| /* Set SLEEPDEEP bit of Cortex System Control Register */ | |||
| SET_BIT(SCB->SCR, ((uint32_t)SCB_SCR_SLEEPDEEP_Msk)); | |||
| } | |||
| /** | |||
| * @brief Configures sleep-on-exit when returning from Handler mode to Thread mode. | |||
| * @note Setting this bit to 1 enables an interrupt-driven application to avoid returning to an | |||
| * empty main application. | |||
| * @rmtoll SCB_SCR SLEEPONEXIT LL_LPM_EnableSleepOnExit | |||
| * @retval None | |||
| */ | |||
| __STATIC_INLINE void LL_LPM_EnableSleepOnExit(void) | |||
| { | |||
| /* Set SLEEPONEXIT bit of Cortex System Control Register */ | |||
| SET_BIT(SCB->SCR, ((uint32_t)SCB_SCR_SLEEPONEXIT_Msk)); | |||
| } | |||
| /** | |||
| * @brief Do not sleep when returning to Thread mode. | |||
| * @rmtoll SCB_SCR SLEEPONEXIT LL_LPM_DisableSleepOnExit | |||
| * @retval None | |||
| */ | |||
| __STATIC_INLINE void LL_LPM_DisableSleepOnExit(void) | |||
| { | |||
| /* Clear SLEEPONEXIT bit of Cortex System Control Register */ | |||
| CLEAR_BIT(SCB->SCR, ((uint32_t)SCB_SCR_SLEEPONEXIT_Msk)); | |||
| } | |||
| /** | |||
| * @brief Enabled events and all interrupts, including disabled interrupts, can wakeup the | |||
| * processor. | |||
| * @rmtoll SCB_SCR SEVEONPEND LL_LPM_EnableEventOnPend | |||
| * @retval None | |||
| */ | |||
| __STATIC_INLINE void LL_LPM_EnableEventOnPend(void) | |||
| { | |||
| /* Set SEVEONPEND bit of Cortex System Control Register */ | |||
| SET_BIT(SCB->SCR, ((uint32_t)SCB_SCR_SEVONPEND_Msk)); | |||
| } | |||
| /** | |||
| * @brief Only enabled interrupts or events can wakeup the processor, disabled interrupts are | |||
| * excluded | |||
| * @rmtoll SCB_SCR SEVEONPEND LL_LPM_DisableEventOnPend | |||
| * @retval None | |||
| */ | |||
| __STATIC_INLINE void LL_LPM_DisableEventOnPend(void) | |||
| { | |||
| /* Clear SEVEONPEND bit of Cortex System Control Register */ | |||
| CLEAR_BIT(SCB->SCR, ((uint32_t)SCB_SCR_SEVONPEND_Msk)); | |||
| } | |||
| /** | |||
| * @} | |||
| */ | |||
| /** @defgroup CORTEX_LL_EF_HANDLER HANDLER | |||
| * @{ | |||
| */ | |||
| /** | |||
| * @brief Enable a fault in System handler control register (SHCSR) | |||
| * @rmtoll SCB_SHCSR MEMFAULTENA LL_HANDLER_EnableFault | |||
| * @param Fault This parameter can be a combination of the following values: | |||
| * @arg @ref LL_HANDLER_FAULT_USG | |||
| * @arg @ref LL_HANDLER_FAULT_BUS | |||
| * @arg @ref LL_HANDLER_FAULT_MEM | |||
| * @retval None | |||
| */ | |||
| __STATIC_INLINE void LL_HANDLER_EnableFault(uint32_t Fault) | |||
| { | |||
| /* Enable the system handler fault */ | |||
| SET_BIT(SCB->SHCSR, Fault); | |||
| } | |||
| /** | |||
| * @brief Disable a fault in System handler control register (SHCSR) | |||
| * @rmtoll SCB_SHCSR MEMFAULTENA LL_HANDLER_DisableFault | |||
| * @param Fault This parameter can be a combination of the following values: | |||
| * @arg @ref LL_HANDLER_FAULT_USG | |||
| * @arg @ref LL_HANDLER_FAULT_BUS | |||
| * @arg @ref LL_HANDLER_FAULT_MEM | |||
| * @retval None | |||
| */ | |||
| __STATIC_INLINE void LL_HANDLER_DisableFault(uint32_t Fault) | |||
| { | |||
| /* Disable the system handler fault */ | |||
| CLEAR_BIT(SCB->SHCSR, Fault); | |||
| } | |||
| /** | |||
| * @} | |||
| */ | |||
| /** @defgroup CORTEX_LL_EF_MCU_INFO MCU INFO | |||
| * @{ | |||
| */ | |||
| /** | |||
| * @brief Get Implementer code | |||
| * @rmtoll SCB_CPUID IMPLEMENTER LL_CPUID_GetImplementer | |||
| * @retval Value should be equal to 0x41 for ARM | |||
| */ | |||
| __STATIC_INLINE uint32_t LL_CPUID_GetImplementer(void) | |||
| { | |||
| return (uint32_t)(READ_BIT(SCB->CPUID, SCB_CPUID_IMPLEMENTER_Msk) >> SCB_CPUID_IMPLEMENTER_Pos); | |||
| } | |||
| /** | |||
| * @brief Get Variant number (The r value in the rnpn product revision identifier) | |||
| * @rmtoll SCB_CPUID VARIANT LL_CPUID_GetVariant | |||
| * @retval Value between 0 and 255 (0x1: revision 1, 0x2: revision 2) | |||
| */ | |||
| __STATIC_INLINE uint32_t LL_CPUID_GetVariant(void) | |||
| { | |||
| return (uint32_t)(READ_BIT(SCB->CPUID, SCB_CPUID_VARIANT_Msk) >> SCB_CPUID_VARIANT_Pos); | |||
| } | |||
| /** | |||
| * @brief Get Constant number | |||
| * @rmtoll SCB_CPUID ARCHITECTURE LL_CPUID_GetConstant | |||
| * @retval Value should be equal to 0xF for Cortex-M3 devices | |||
| */ | |||
| __STATIC_INLINE uint32_t LL_CPUID_GetConstant(void) | |||
| { | |||
| return (uint32_t)(READ_BIT(SCB->CPUID, SCB_CPUID_ARCHITECTURE_Msk) >> SCB_CPUID_ARCHITECTURE_Pos); | |||
| } | |||
| /** | |||
| * @brief Get Part number | |||
| * @rmtoll SCB_CPUID PARTNO LL_CPUID_GetParNo | |||
| * @retval Value should be equal to 0xC23 for Cortex-M3 | |||
| */ | |||
| __STATIC_INLINE uint32_t LL_CPUID_GetParNo(void) | |||
| { | |||
| return (uint32_t)(READ_BIT(SCB->CPUID, SCB_CPUID_PARTNO_Msk) >> SCB_CPUID_PARTNO_Pos); | |||
| } | |||
| /** | |||
| * @brief Get Revision number (The p value in the rnpn product revision identifier, indicates patch release) | |||
| * @rmtoll SCB_CPUID REVISION LL_CPUID_GetRevision | |||
| * @retval Value between 0 and 255 (0x0: patch 0, 0x1: patch 1) | |||
| */ | |||
| __STATIC_INLINE uint32_t LL_CPUID_GetRevision(void) | |||
| { | |||
| return (uint32_t)(READ_BIT(SCB->CPUID, SCB_CPUID_REVISION_Msk) >> SCB_CPUID_REVISION_Pos); | |||
| } | |||
| /** | |||
| * @} | |||
| */ | |||
| #if __MPU_PRESENT | |||
| /** @defgroup CORTEX_LL_EF_MPU MPU | |||
| * @{ | |||
| */ | |||
| /** | |||
| * @brief Enable MPU with input options | |||
| * @rmtoll MPU_CTRL ENABLE LL_MPU_Enable | |||
| * @param Options This parameter can be one of the following values: | |||
| * @arg @ref LL_MPU_CTRL_HFNMI_PRIVDEF_NONE | |||
| * @arg @ref LL_MPU_CTRL_HARDFAULT_NMI | |||
| * @arg @ref LL_MPU_CTRL_PRIVILEGED_DEFAULT | |||
| * @arg @ref LL_MPU_CTRL_HFNMI_PRIVDEF | |||
| * @retval None | |||
| */ | |||
| __STATIC_INLINE void LL_MPU_Enable(uint32_t Options) | |||
| { | |||
| /* Enable the MPU*/ | |||
| WRITE_REG(MPU->CTRL, (MPU_CTRL_ENABLE_Msk | Options)); | |||
| /* Ensure MPU settings take effects */ | |||
| __DSB(); | |||
| /* Sequence instruction fetches using update settings */ | |||
| __ISB(); | |||
| } | |||
| /** | |||
| * @brief Disable MPU | |||
| * @rmtoll MPU_CTRL ENABLE LL_MPU_Disable | |||
| * @retval None | |||
| */ | |||
| __STATIC_INLINE void LL_MPU_Disable(void) | |||
| { | |||
| /* Make sure outstanding transfers are done */ | |||
| __DMB(); | |||
| /* Disable MPU*/ | |||
| WRITE_REG(MPU->CTRL, 0U); | |||
| } | |||
| /** | |||
| * @brief Check if MPU is enabled or not | |||
| * @rmtoll MPU_CTRL ENABLE LL_MPU_IsEnabled | |||
| * @retval State of bit (1 or 0). | |||
| */ | |||
| __STATIC_INLINE uint32_t LL_MPU_IsEnabled(void) | |||
| { | |||
| return (READ_BIT(MPU->CTRL, MPU_CTRL_ENABLE_Msk) == (MPU_CTRL_ENABLE_Msk)); | |||
| } | |||
| /** | |||
| * @brief Enable a MPU region | |||
| * @rmtoll MPU_RASR ENABLE LL_MPU_EnableRegion | |||
| * @param Region This parameter can be one of the following values: | |||
| * @arg @ref LL_MPU_REGION_NUMBER0 | |||
| * @arg @ref LL_MPU_REGION_NUMBER1 | |||
| * @arg @ref LL_MPU_REGION_NUMBER2 | |||
| * @arg @ref LL_MPU_REGION_NUMBER3 | |||
| * @arg @ref LL_MPU_REGION_NUMBER4 | |||
| * @arg @ref LL_MPU_REGION_NUMBER5 | |||
| * @arg @ref LL_MPU_REGION_NUMBER6 | |||
| * @arg @ref LL_MPU_REGION_NUMBER7 | |||
| * @retval None | |||
| */ | |||
| __STATIC_INLINE void LL_MPU_EnableRegion(uint32_t Region) | |||
| { | |||
| /* Set Region number */ | |||
| WRITE_REG(MPU->RNR, Region); | |||
| /* Enable the MPU region */ | |||
| SET_BIT(MPU->RASR, MPU_RASR_ENABLE_Msk); | |||
| } | |||
| /** | |||
| * @brief Configure and enable a region | |||
| * @rmtoll MPU_RNR REGION LL_MPU_ConfigRegion\n | |||
| * MPU_RBAR REGION LL_MPU_ConfigRegion\n | |||
| * MPU_RBAR ADDR LL_MPU_ConfigRegion\n | |||
| * MPU_RASR XN LL_MPU_ConfigRegion\n | |||
| * MPU_RASR AP LL_MPU_ConfigRegion\n | |||
| * MPU_RASR S LL_MPU_ConfigRegion\n | |||
| * MPU_RASR C LL_MPU_ConfigRegion\n | |||
| * MPU_RASR B LL_MPU_ConfigRegion\n | |||
| * MPU_RASR SIZE LL_MPU_ConfigRegion | |||
| * @param Region This parameter can be one of the following values: | |||
| * @arg @ref LL_MPU_REGION_NUMBER0 | |||
| * @arg @ref LL_MPU_REGION_NUMBER1 | |||
| * @arg @ref LL_MPU_REGION_NUMBER2 | |||
| * @arg @ref LL_MPU_REGION_NUMBER3 | |||
| * @arg @ref LL_MPU_REGION_NUMBER4 | |||
| * @arg @ref LL_MPU_REGION_NUMBER5 | |||
| * @arg @ref LL_MPU_REGION_NUMBER6 | |||
| * @arg @ref LL_MPU_REGION_NUMBER7 | |||
| * @param Address Value of region base address | |||
| * @param SubRegionDisable Sub-region disable value between Min_Data = 0x00 and Max_Data = 0xFF | |||
| * @param Attributes This parameter can be a combination of the following values: | |||
| * @arg @ref LL_MPU_REGION_SIZE_32B or @ref LL_MPU_REGION_SIZE_64B or @ref LL_MPU_REGION_SIZE_128B or @ref LL_MPU_REGION_SIZE_256B or @ref LL_MPU_REGION_SIZE_512B | |||
| * or @ref LL_MPU_REGION_SIZE_1KB or @ref LL_MPU_REGION_SIZE_2KB or @ref LL_MPU_REGION_SIZE_4KB or @ref LL_MPU_REGION_SIZE_8KB or @ref LL_MPU_REGION_SIZE_16KB | |||
| * or @ref LL_MPU_REGION_SIZE_32KB or @ref LL_MPU_REGION_SIZE_64KB or @ref LL_MPU_REGION_SIZE_128KB or @ref LL_MPU_REGION_SIZE_256KB or @ref LL_MPU_REGION_SIZE_512KB | |||
| * or @ref LL_MPU_REGION_SIZE_1MB or @ref LL_MPU_REGION_SIZE_2MB or @ref LL_MPU_REGION_SIZE_4MB or @ref LL_MPU_REGION_SIZE_8MB or @ref LL_MPU_REGION_SIZE_16MB | |||
| * or @ref LL_MPU_REGION_SIZE_32MB or @ref LL_MPU_REGION_SIZE_64MB or @ref LL_MPU_REGION_SIZE_128MB or @ref LL_MPU_REGION_SIZE_256MB or @ref LL_MPU_REGION_SIZE_512MB | |||
| * or @ref LL_MPU_REGION_SIZE_1GB or @ref LL_MPU_REGION_SIZE_2GB or @ref LL_MPU_REGION_SIZE_4GB | |||
| * @arg @ref LL_MPU_REGION_NO_ACCESS or @ref LL_MPU_REGION_PRIV_RW or @ref LL_MPU_REGION_PRIV_RW_URO or @ref LL_MPU_REGION_FULL_ACCESS | |||
| * or @ref LL_MPU_REGION_PRIV_RO or @ref LL_MPU_REGION_PRIV_RO_URO | |||
| * @arg @ref LL_MPU_TEX_LEVEL0 or @ref LL_MPU_TEX_LEVEL1 or @ref LL_MPU_TEX_LEVEL2 or @ref LL_MPU_TEX_LEVEL4 | |||
| * @arg @ref LL_MPU_INSTRUCTION_ACCESS_ENABLE or @ref LL_MPU_INSTRUCTION_ACCESS_DISABLE | |||
| * @arg @ref LL_MPU_ACCESS_SHAREABLE or @ref LL_MPU_ACCESS_NOT_SHAREABLE | |||
| * @arg @ref LL_MPU_ACCESS_CACHEABLE or @ref LL_MPU_ACCESS_NOT_CACHEABLE | |||
| * @arg @ref LL_MPU_ACCESS_BUFFERABLE or @ref LL_MPU_ACCESS_NOT_BUFFERABLE | |||
| * @retval None | |||
| */ | |||
| __STATIC_INLINE void LL_MPU_ConfigRegion(uint32_t Region, uint32_t SubRegionDisable, uint32_t Address, uint32_t Attributes) | |||
| { | |||
| /* Set Region number */ | |||
| WRITE_REG(MPU->RNR, Region); | |||
| /* Set base address */ | |||
| WRITE_REG(MPU->RBAR, (Address & 0xFFFFFFE0U)); | |||
| /* Configure MPU */ | |||
| WRITE_REG(MPU->RASR, (MPU_RASR_ENABLE_Msk | Attributes | SubRegionDisable << MPU_RASR_SRD_Pos)); | |||
| } | |||
| /** | |||
| * @brief Disable a region | |||
| * @rmtoll MPU_RNR REGION LL_MPU_DisableRegion\n | |||
| * MPU_RASR ENABLE LL_MPU_DisableRegion | |||
| * @param Region This parameter can be one of the following values: | |||
| * @arg @ref LL_MPU_REGION_NUMBER0 | |||
| * @arg @ref LL_MPU_REGION_NUMBER1 | |||
| * @arg @ref LL_MPU_REGION_NUMBER2 | |||
| * @arg @ref LL_MPU_REGION_NUMBER3 | |||
| * @arg @ref LL_MPU_REGION_NUMBER4 | |||
| * @arg @ref LL_MPU_REGION_NUMBER5 | |||
| * @arg @ref LL_MPU_REGION_NUMBER6 | |||
| * @arg @ref LL_MPU_REGION_NUMBER7 | |||
| * @retval None | |||
| */ | |||
| __STATIC_INLINE void LL_MPU_DisableRegion(uint32_t Region) | |||
| { | |||
| /* Set Region number */ | |||
| WRITE_REG(MPU->RNR, Region); | |||
| /* Disable the MPU region */ | |||
| CLEAR_BIT(MPU->RASR, MPU_RASR_ENABLE_Msk); | |||
| } | |||
| /** | |||
| * @} | |||
| */ | |||
| #endif /* __MPU_PRESENT */ | |||
| /** | |||
| * @} | |||
| */ | |||
| /** | |||
| * @} | |||
| */ | |||
| /** | |||
| * @} | |||
| */ | |||
| #ifdef __cplusplus | |||
| } | |||
| #endif | |||
| #endif /* __STM32F1xx_LL_CORTEX_H */ | |||
| @ -0,0 +1,886 @@ | |||
| /** | |||
| ****************************************************************************** | |||
| * @file stm32f1xx_ll_exti.h | |||
| * @author MCD Application Team | |||
| * @brief Header file of EXTI LL module. | |||
| ****************************************************************************** | |||
| * @attention | |||
| * | |||
| * Copyright (c) 2016 STMicroelectronics. | |||
| * All rights reserved. | |||
| * | |||
| * This software is licensed under terms that can be found in the LICENSE file | |||
| * in the root directory of this software component. | |||
| * If no LICENSE file comes with this software, it is provided AS-IS. | |||
| * | |||
| ****************************************************************************** | |||
| */ | |||
| /* Define to prevent recursive inclusion -------------------------------------*/ | |||
| #ifndef STM32F1xx_LL_EXTI_H | |||
| #define STM32F1xx_LL_EXTI_H | |||
| #ifdef __cplusplus | |||
| extern "C" { | |||
| #endif | |||
| /* Includes ------------------------------------------------------------------*/ | |||
| #include "stm32f1xx.h" | |||
| /** @addtogroup STM32F1xx_LL_Driver | |||
| * @{ | |||
| */ | |||
| #if defined (EXTI) | |||
| /** @defgroup EXTI_LL EXTI | |||
| * @{ | |||
| */ | |||
| /* Private types -------------------------------------------------------------*/ | |||
| /* Private variables ---------------------------------------------------------*/ | |||
| /* Private constants ---------------------------------------------------------*/ | |||
| /* Private Macros ------------------------------------------------------------*/ | |||
| #if defined(USE_FULL_LL_DRIVER) | |||
| /** @defgroup EXTI_LL_Private_Macros EXTI Private Macros | |||
| * @{ | |||
| */ | |||
| /** | |||
| * @} | |||
| */ | |||
| #endif /*USE_FULL_LL_DRIVER*/ | |||
| /* Exported types ------------------------------------------------------------*/ | |||
| #if defined(USE_FULL_LL_DRIVER) | |||
| /** @defgroup EXTI_LL_ES_INIT EXTI Exported Init structure | |||
| * @{ | |||
| */ | |||
| typedef struct | |||
| { | |||
| uint32_t Line_0_31; /*!< Specifies the EXTI lines to be enabled or disabled for Lines in range 0 to 31 | |||
| This parameter can be any combination of @ref EXTI_LL_EC_LINE */ | |||
| FunctionalState LineCommand; /*!< Specifies the new state of the selected EXTI lines. | |||
| This parameter can be set either to ENABLE or DISABLE */ | |||
| uint8_t Mode; /*!< Specifies the mode for the EXTI lines. | |||
| This parameter can be a value of @ref EXTI_LL_EC_MODE. */ | |||
| uint8_t Trigger; /*!< Specifies the trigger signal active edge for the EXTI lines. | |||
| This parameter can be a value of @ref EXTI_LL_EC_TRIGGER. */ | |||
| } LL_EXTI_InitTypeDef; | |||
| /** | |||
| * @} | |||
| */ | |||
| #endif /*USE_FULL_LL_DRIVER*/ | |||
| /* Exported constants --------------------------------------------------------*/ | |||
| /** @defgroup EXTI_LL_Exported_Constants EXTI Exported Constants | |||
| * @{ | |||
| */ | |||
| /** @defgroup EXTI_LL_EC_LINE LINE | |||
| * @{ | |||
| */ | |||
| #define LL_EXTI_LINE_0 EXTI_IMR_IM0 /*!< Extended line 0 */ | |||
| #define LL_EXTI_LINE_1 EXTI_IMR_IM1 /*!< Extended line 1 */ | |||
| #define LL_EXTI_LINE_2 EXTI_IMR_IM2 /*!< Extended line 2 */ | |||
| #define LL_EXTI_LINE_3 EXTI_IMR_IM3 /*!< Extended line 3 */ | |||
| #define LL_EXTI_LINE_4 EXTI_IMR_IM4 /*!< Extended line 4 */ | |||
| #define LL_EXTI_LINE_5 EXTI_IMR_IM5 /*!< Extended line 5 */ | |||
| #define LL_EXTI_LINE_6 EXTI_IMR_IM6 /*!< Extended line 6 */ | |||
| #define LL_EXTI_LINE_7 EXTI_IMR_IM7 /*!< Extended line 7 */ | |||
| #define LL_EXTI_LINE_8 EXTI_IMR_IM8 /*!< Extended line 8 */ | |||
| #define LL_EXTI_LINE_9 EXTI_IMR_IM9 /*!< Extended line 9 */ | |||
| #define LL_EXTI_LINE_10 EXTI_IMR_IM10 /*!< Extended line 10 */ | |||
| #define LL_EXTI_LINE_11 EXTI_IMR_IM11 /*!< Extended line 11 */ | |||
| #define LL_EXTI_LINE_12 EXTI_IMR_IM12 /*!< Extended line 12 */ | |||
| #define LL_EXTI_LINE_13 EXTI_IMR_IM13 /*!< Extended line 13 */ | |||
| #define LL_EXTI_LINE_14 EXTI_IMR_IM14 /*!< Extended line 14 */ | |||
| #define LL_EXTI_LINE_15 EXTI_IMR_IM15 /*!< Extended line 15 */ | |||
| #if defined(EXTI_IMR_IM16) | |||
| #define LL_EXTI_LINE_16 EXTI_IMR_IM16 /*!< Extended line 16 */ | |||
| #endif | |||
| #define LL_EXTI_LINE_17 EXTI_IMR_IM17 /*!< Extended line 17 */ | |||
| #if defined(EXTI_IMR_IM18) | |||
| #define LL_EXTI_LINE_18 EXTI_IMR_IM18 /*!< Extended line 18 */ | |||
| #endif | |||
| #if defined(EXTI_IMR_IM19) | |||
| #define LL_EXTI_LINE_19 EXTI_IMR_IM19 /*!< Extended line 19 */ | |||
| #endif | |||
| #if defined(EXTI_IMR_IM20) | |||
| #define LL_EXTI_LINE_20 EXTI_IMR_IM20 /*!< Extended line 20 */ | |||
| #endif | |||
| #if defined(EXTI_IMR_IM21) | |||
| #define LL_EXTI_LINE_21 EXTI_IMR_IM21 /*!< Extended line 21 */ | |||
| #endif | |||
| #if defined(EXTI_IMR_IM22) | |||
| #define LL_EXTI_LINE_22 EXTI_IMR_IM22 /*!< Extended line 22 */ | |||
| #endif | |||
| #if defined(EXTI_IMR_IM23) | |||
| #define LL_EXTI_LINE_23 EXTI_IMR_IM23 /*!< Extended line 23 */ | |||
| #endif | |||
| #if defined(EXTI_IMR_IM24) | |||
| #define LL_EXTI_LINE_24 EXTI_IMR_IM24 /*!< Extended line 24 */ | |||
| #endif | |||
| #if defined(EXTI_IMR_IM25) | |||
| #define LL_EXTI_LINE_25 EXTI_IMR_IM25 /*!< Extended line 25 */ | |||
| #endif | |||
| #if defined(EXTI_IMR_IM26) | |||
| #define LL_EXTI_LINE_26 EXTI_IMR_IM26 /*!< Extended line 26 */ | |||
| #endif | |||
| #if defined(EXTI_IMR_IM27) | |||
| #define LL_EXTI_LINE_27 EXTI_IMR_IM27 /*!< Extended line 27 */ | |||
| #endif | |||
| #if defined(EXTI_IMR_IM28) | |||
| #define LL_EXTI_LINE_28 EXTI_IMR_IM28 /*!< Extended line 28 */ | |||
| #endif | |||
| #if defined(EXTI_IMR_IM29) | |||
| #define LL_EXTI_LINE_29 EXTI_IMR_IM29 /*!< Extended line 29 */ | |||
| #endif | |||
| #if defined(EXTI_IMR_IM30) | |||
| #define LL_EXTI_LINE_30 EXTI_IMR_IM30 /*!< Extended line 30 */ | |||
| #endif | |||
| #if defined(EXTI_IMR_IM31) | |||
| #define LL_EXTI_LINE_31 EXTI_IMR_IM31 /*!< Extended line 31 */ | |||
| #endif | |||
| #define LL_EXTI_LINE_ALL_0_31 EXTI_IMR_IM /*!< All Extended line not reserved*/ | |||
| #define LL_EXTI_LINE_ALL (0xFFFFFFFFU) /*!< All Extended line */ | |||
| #if defined(USE_FULL_LL_DRIVER) | |||
| #define LL_EXTI_LINE_NONE (0x00000000U) /*!< None Extended line */ | |||
| #endif /*USE_FULL_LL_DRIVER*/ | |||
| /** | |||
| * @} | |||
| */ | |||
| #if defined(USE_FULL_LL_DRIVER) | |||
| /** @defgroup EXTI_LL_EC_MODE Mode | |||
| * @{ | |||
| */ | |||
| #define LL_EXTI_MODE_IT ((uint8_t)0x00) /*!< Interrupt Mode */ | |||
| #define LL_EXTI_MODE_EVENT ((uint8_t)0x01) /*!< Event Mode */ | |||
| #define LL_EXTI_MODE_IT_EVENT ((uint8_t)0x02) /*!< Interrupt & Event Mode */ | |||
| /** | |||
| * @} | |||
| */ | |||
| /** @defgroup EXTI_LL_EC_TRIGGER Edge Trigger | |||
| * @{ | |||
| */ | |||
| #define LL_EXTI_TRIGGER_NONE ((uint8_t)0x00) /*!< No Trigger Mode */ | |||
| #define LL_EXTI_TRIGGER_RISING ((uint8_t)0x01) /*!< Trigger Rising Mode */ | |||
| #define LL_EXTI_TRIGGER_FALLING ((uint8_t)0x02) /*!< Trigger Falling Mode */ | |||
| #define LL_EXTI_TRIGGER_RISING_FALLING ((uint8_t)0x03) /*!< Trigger Rising & Falling Mode */ | |||
| /** | |||
| * @} | |||
| */ | |||
| #endif /*USE_FULL_LL_DRIVER*/ | |||
| /** | |||
| * @} | |||
| */ | |||
| /* Exported macro ------------------------------------------------------------*/ | |||
| /** @defgroup EXTI_LL_Exported_Macros EXTI Exported Macros | |||
| * @{ | |||
| */ | |||
| /** @defgroup EXTI_LL_EM_WRITE_READ Common Write and read registers Macros | |||
| * @{ | |||
| */ | |||
| /** | |||
| * @brief Write a value in EXTI register | |||
| * @param __REG__ Register to be written | |||
| * @param __VALUE__ Value to be written in the register | |||
| * @retval None | |||
| */ | |||
| #define LL_EXTI_WriteReg(__REG__, __VALUE__) WRITE_REG(EXTI->__REG__, (__VALUE__)) | |||
| /** | |||
| * @brief Read a value in EXTI register | |||
| * @param __REG__ Register to be read | |||
| * @retval Register value | |||
| */ | |||
| #define LL_EXTI_ReadReg(__REG__) READ_REG(EXTI->__REG__) | |||
| /** | |||
| * @} | |||
| */ | |||
| /** | |||
| * @} | |||
| */ | |||
| /* Exported functions --------------------------------------------------------*/ | |||
| /** @defgroup EXTI_LL_Exported_Functions EXTI Exported Functions | |||
| * @{ | |||
| */ | |||
| /** @defgroup EXTI_LL_EF_IT_Management IT_Management | |||
| * @{ | |||
| */ | |||
| /** | |||
| * @brief Enable ExtiLine Interrupt request for Lines in range 0 to 31 | |||
| * @note The reset value for the direct or internal lines (see RM) | |||
| * is set to 1 in order to enable the interrupt by default. | |||
| * Bits are set automatically at Power on. | |||
| * @rmtoll IMR IMx LL_EXTI_EnableIT_0_31 | |||
| * @param ExtiLine This parameter can be one of the following values: | |||
| * @arg @ref LL_EXTI_LINE_0 | |||
| * @arg @ref LL_EXTI_LINE_1 | |||
| * @arg @ref LL_EXTI_LINE_2 | |||
| * @arg @ref LL_EXTI_LINE_3 | |||
| * @arg @ref LL_EXTI_LINE_4 | |||
| * @arg @ref LL_EXTI_LINE_5 | |||
| * @arg @ref LL_EXTI_LINE_6 | |||
| * @arg @ref LL_EXTI_LINE_7 | |||
| * @arg @ref LL_EXTI_LINE_8 | |||
| * @arg @ref LL_EXTI_LINE_9 | |||
| * @arg @ref LL_EXTI_LINE_10 | |||
| * @arg @ref LL_EXTI_LINE_11 | |||
| * @arg @ref LL_EXTI_LINE_12 | |||
| * @arg @ref LL_EXTI_LINE_13 | |||
| * @arg @ref LL_EXTI_LINE_14 | |||
| * @arg @ref LL_EXTI_LINE_15 | |||
| * @arg @ref LL_EXTI_LINE_16 | |||
| * @arg @ref LL_EXTI_LINE_17 | |||
| * @arg @ref LL_EXTI_LINE_18 | |||
| * @arg @ref LL_EXTI_LINE_19 | |||
| * @arg @ref LL_EXTI_LINE_ALL_0_31 | |||
| * @note Please check each device line mapping for EXTI Line availability | |||
| * @retval None | |||
| */ | |||
| __STATIC_INLINE void LL_EXTI_EnableIT_0_31(uint32_t ExtiLine) | |||
| { | |||
| SET_BIT(EXTI->IMR, ExtiLine); | |||
| } | |||
| /** | |||
| * @brief Disable ExtiLine Interrupt request for Lines in range 0 to 31 | |||
| * @note The reset value for the direct or internal lines (see RM) | |||
| * is set to 1 in order to enable the interrupt by default. | |||
| * Bits are set automatically at Power on. | |||
| * @rmtoll IMR IMx LL_EXTI_DisableIT_0_31 | |||
| * @param ExtiLine This parameter can be one of the following values: | |||
| * @arg @ref LL_EXTI_LINE_0 | |||
| * @arg @ref LL_EXTI_LINE_1 | |||
| * @arg @ref LL_EXTI_LINE_2 | |||
| * @arg @ref LL_EXTI_LINE_3 | |||
| * @arg @ref LL_EXTI_LINE_4 | |||
| * @arg @ref LL_EXTI_LINE_5 | |||
| * @arg @ref LL_EXTI_LINE_6 | |||
| * @arg @ref LL_EXTI_LINE_7 | |||
| * @arg @ref LL_EXTI_LINE_8 | |||
| * @arg @ref LL_EXTI_LINE_9 | |||
| * @arg @ref LL_EXTI_LINE_10 | |||
| * @arg @ref LL_EXTI_LINE_11 | |||
| * @arg @ref LL_EXTI_LINE_12 | |||
| * @arg @ref LL_EXTI_LINE_13 | |||
| * @arg @ref LL_EXTI_LINE_14 | |||
| * @arg @ref LL_EXTI_LINE_15 | |||
| * @arg @ref LL_EXTI_LINE_16 | |||
| * @arg @ref LL_EXTI_LINE_17 | |||
| * @arg @ref LL_EXTI_LINE_18 | |||
| * @arg @ref LL_EXTI_LINE_19 | |||
| * @arg @ref LL_EXTI_LINE_ALL_0_31 | |||
| * @note Please check each device line mapping for EXTI Line availability | |||
| * @retval None | |||
| */ | |||
| __STATIC_INLINE void LL_EXTI_DisableIT_0_31(uint32_t ExtiLine) | |||
| { | |||
| CLEAR_BIT(EXTI->IMR, ExtiLine); | |||
| } | |||
| /** | |||
| * @brief Indicate if ExtiLine Interrupt request is enabled for Lines in range 0 to 31 | |||
| * @note The reset value for the direct or internal lines (see RM) | |||
| * is set to 1 in order to enable the interrupt by default. | |||
| * Bits are set automatically at Power on. | |||
| * @rmtoll IMR IMx LL_EXTI_IsEnabledIT_0_31 | |||
| * @param ExtiLine This parameter can be one of the following values: | |||
| * @arg @ref LL_EXTI_LINE_0 | |||
| * @arg @ref LL_EXTI_LINE_1 | |||
| * @arg @ref LL_EXTI_LINE_2 | |||
| * @arg @ref LL_EXTI_LINE_3 | |||
| * @arg @ref LL_EXTI_LINE_4 | |||
| * @arg @ref LL_EXTI_LINE_5 | |||
| * @arg @ref LL_EXTI_LINE_6 | |||
| * @arg @ref LL_EXTI_LINE_7 | |||
| * @arg @ref LL_EXTI_LINE_8 | |||
| * @arg @ref LL_EXTI_LINE_9 | |||
| * @arg @ref LL_EXTI_LINE_10 | |||
| * @arg @ref LL_EXTI_LINE_11 | |||
| * @arg @ref LL_EXTI_LINE_12 | |||
| * @arg @ref LL_EXTI_LINE_13 | |||
| * @arg @ref LL_EXTI_LINE_14 | |||
| * @arg @ref LL_EXTI_LINE_15 | |||
| * @arg @ref LL_EXTI_LINE_16 | |||
| * @arg @ref LL_EXTI_LINE_17 | |||
| * @arg @ref LL_EXTI_LINE_18 | |||
| * @arg @ref LL_EXTI_LINE_19 | |||
| * @arg @ref LL_EXTI_LINE_ALL_0_31 | |||
| * @note Please check each device line mapping for EXTI Line availability | |||
| * @retval State of bit (1 or 0). | |||
| */ | |||
| __STATIC_INLINE uint32_t LL_EXTI_IsEnabledIT_0_31(uint32_t ExtiLine) | |||
| { | |||
| return (READ_BIT(EXTI->IMR, ExtiLine) == (ExtiLine)); | |||
| } | |||
| /** | |||
| * @} | |||
| */ | |||
| /** @defgroup EXTI_LL_EF_Event_Management Event_Management | |||
| * @{ | |||
| */ | |||
| /** | |||
| * @brief Enable ExtiLine Event request for Lines in range 0 to 31 | |||
| * @rmtoll EMR EMx LL_EXTI_EnableEvent_0_31 | |||
| * @param ExtiLine This parameter can be one of the following values: | |||
| * @arg @ref LL_EXTI_LINE_0 | |||
| * @arg @ref LL_EXTI_LINE_1 | |||
| * @arg @ref LL_EXTI_LINE_2 | |||
| * @arg @ref LL_EXTI_LINE_3 | |||
| * @arg @ref LL_EXTI_LINE_4 | |||
| * @arg @ref LL_EXTI_LINE_5 | |||
| * @arg @ref LL_EXTI_LINE_6 | |||
| * @arg @ref LL_EXTI_LINE_7 | |||
| * @arg @ref LL_EXTI_LINE_8 | |||
| * @arg @ref LL_EXTI_LINE_9 | |||
| * @arg @ref LL_EXTI_LINE_10 | |||
| * @arg @ref LL_EXTI_LINE_11 | |||
| * @arg @ref LL_EXTI_LINE_12 | |||
| * @arg @ref LL_EXTI_LINE_13 | |||
| * @arg @ref LL_EXTI_LINE_14 | |||
| * @arg @ref LL_EXTI_LINE_15 | |||
| * @arg @ref LL_EXTI_LINE_16 | |||
| * @arg @ref LL_EXTI_LINE_17 | |||
| * @arg @ref LL_EXTI_LINE_18 | |||
| * @arg @ref LL_EXTI_LINE_19 | |||
| * @arg @ref LL_EXTI_LINE_ALL_0_31 | |||
| * @note Please check each device line mapping for EXTI Line availability | |||
| * @retval None | |||
| */ | |||
| __STATIC_INLINE void LL_EXTI_EnableEvent_0_31(uint32_t ExtiLine) | |||
| { | |||
| SET_BIT(EXTI->EMR, ExtiLine); | |||
| } | |||
| /** | |||
| * @brief Disable ExtiLine Event request for Lines in range 0 to 31 | |||
| * @rmtoll EMR EMx LL_EXTI_DisableEvent_0_31 | |||
| * @param ExtiLine This parameter can be one of the following values: | |||
| * @arg @ref LL_EXTI_LINE_0 | |||
| * @arg @ref LL_EXTI_LINE_1 | |||
| * @arg @ref LL_EXTI_LINE_2 | |||
| * @arg @ref LL_EXTI_LINE_3 | |||
| * @arg @ref LL_EXTI_LINE_4 | |||
| * @arg @ref LL_EXTI_LINE_5 | |||
| * @arg @ref LL_EXTI_LINE_6 | |||
| * @arg @ref LL_EXTI_LINE_7 | |||
| * @arg @ref LL_EXTI_LINE_8 | |||
| * @arg @ref LL_EXTI_LINE_9 | |||
| * @arg @ref LL_EXTI_LINE_10 | |||
| * @arg @ref LL_EXTI_LINE_11 | |||
| * @arg @ref LL_EXTI_LINE_12 | |||
| * @arg @ref LL_EXTI_LINE_13 | |||
| * @arg @ref LL_EXTI_LINE_14 | |||
| * @arg @ref LL_EXTI_LINE_15 | |||
| * @arg @ref LL_EXTI_LINE_16 | |||
| * @arg @ref LL_EXTI_LINE_17 | |||
| * @arg @ref LL_EXTI_LINE_18 | |||
| * @arg @ref LL_EXTI_LINE_19 | |||
| * @arg @ref LL_EXTI_LINE_ALL_0_31 | |||
| * @note Please check each device line mapping for EXTI Line availability | |||
| * @retval None | |||
| */ | |||
| __STATIC_INLINE void LL_EXTI_DisableEvent_0_31(uint32_t ExtiLine) | |||
| { | |||
| CLEAR_BIT(EXTI->EMR, ExtiLine); | |||
| } | |||
| /** | |||
| * @brief Indicate if ExtiLine Event request is enabled for Lines in range 0 to 31 | |||
| * @rmtoll EMR EMx LL_EXTI_IsEnabledEvent_0_31 | |||
| * @param ExtiLine This parameter can be one of the following values: | |||
| * @arg @ref LL_EXTI_LINE_0 | |||
| * @arg @ref LL_EXTI_LINE_1 | |||
| * @arg @ref LL_EXTI_LINE_2 | |||
| * @arg @ref LL_EXTI_LINE_3 | |||
| * @arg @ref LL_EXTI_LINE_4 | |||
| * @arg @ref LL_EXTI_LINE_5 | |||
| * @arg @ref LL_EXTI_LINE_6 | |||
| * @arg @ref LL_EXTI_LINE_7 | |||
| * @arg @ref LL_EXTI_LINE_8 | |||
| * @arg @ref LL_EXTI_LINE_9 | |||
| * @arg @ref LL_EXTI_LINE_10 | |||
| * @arg @ref LL_EXTI_LINE_11 | |||
| * @arg @ref LL_EXTI_LINE_12 | |||
| * @arg @ref LL_EXTI_LINE_13 | |||
| * @arg @ref LL_EXTI_LINE_14 | |||
| * @arg @ref LL_EXTI_LINE_15 | |||
| * @arg @ref LL_EXTI_LINE_16 | |||
| * @arg @ref LL_EXTI_LINE_17 | |||
| * @arg @ref LL_EXTI_LINE_18 | |||
| * @arg @ref LL_EXTI_LINE_19 | |||
| * @arg @ref LL_EXTI_LINE_ALL_0_31 | |||
| * @note Please check each device line mapping for EXTI Line availability | |||
| * @retval State of bit (1 or 0). | |||
| */ | |||
| __STATIC_INLINE uint32_t LL_EXTI_IsEnabledEvent_0_31(uint32_t ExtiLine) | |||
| { | |||
| return (READ_BIT(EXTI->EMR, ExtiLine) == (ExtiLine)); | |||
| } | |||
| /** | |||
| * @} | |||
| */ | |||
| /** @defgroup EXTI_LL_EF_Rising_Trigger_Management Rising_Trigger_Management | |||
| * @{ | |||
| */ | |||
| /** | |||
| * @brief Enable ExtiLine Rising Edge Trigger for Lines in range 0 to 31 | |||
| * @note The configurable wakeup lines are edge-triggered. No glitch must be | |||
| * generated on these lines. If a rising edge on a configurable interrupt | |||
| * line occurs during a write operation in the EXTI_RTSR register, the | |||
| * pending bit is not set. | |||
| * Rising and falling edge triggers can be set for | |||
| * the same interrupt line. In this case, both generate a trigger | |||
| * condition. | |||
| * @rmtoll RTSR RTx LL_EXTI_EnableRisingTrig_0_31 | |||
| * @param ExtiLine This parameter can be a combination of the following values: | |||
| * @arg @ref LL_EXTI_LINE_0 | |||
| * @arg @ref LL_EXTI_LINE_1 | |||
| * @arg @ref LL_EXTI_LINE_2 | |||
| * @arg @ref LL_EXTI_LINE_3 | |||
| * @arg @ref LL_EXTI_LINE_4 | |||
| * @arg @ref LL_EXTI_LINE_5 | |||
| * @arg @ref LL_EXTI_LINE_6 | |||
| * @arg @ref LL_EXTI_LINE_7 | |||
| * @arg @ref LL_EXTI_LINE_8 | |||
| * @arg @ref LL_EXTI_LINE_9 | |||
| * @arg @ref LL_EXTI_LINE_10 | |||
| * @arg @ref LL_EXTI_LINE_11 | |||
| * @arg @ref LL_EXTI_LINE_12 | |||
| * @arg @ref LL_EXTI_LINE_13 | |||
| * @arg @ref LL_EXTI_LINE_14 | |||
| * @arg @ref LL_EXTI_LINE_15 | |||
| * @arg @ref LL_EXTI_LINE_16 | |||
| * @arg @ref LL_EXTI_LINE_18 | |||
| * @arg @ref LL_EXTI_LINE_19 | |||
| * @note Please check each device line mapping for EXTI Line availability | |||
| * @retval None | |||
| */ | |||
| __STATIC_INLINE void LL_EXTI_EnableRisingTrig_0_31(uint32_t ExtiLine) | |||
| { | |||
| SET_BIT(EXTI->RTSR, ExtiLine); | |||
| } | |||
| /** | |||
| * @brief Disable ExtiLine Rising Edge Trigger for Lines in range 0 to 31 | |||
| * @note The configurable wakeup lines are edge-triggered. No glitch must be | |||
| * generated on these lines. If a rising edge on a configurable interrupt | |||
| * line occurs during a write operation in the EXTI_RTSR register, the | |||
| * pending bit is not set. | |||
| * Rising and falling edge triggers can be set for | |||
| * the same interrupt line. In this case, both generate a trigger | |||
| * condition. | |||
| * @rmtoll RTSR RTx LL_EXTI_DisableRisingTrig_0_31 | |||
| * @param ExtiLine This parameter can be a combination of the following values: | |||
| * @arg @ref LL_EXTI_LINE_0 | |||
| * @arg @ref LL_EXTI_LINE_1 | |||
| * @arg @ref LL_EXTI_LINE_2 | |||
| * @arg @ref LL_EXTI_LINE_3 | |||
| * @arg @ref LL_EXTI_LINE_4 | |||
| * @arg @ref LL_EXTI_LINE_5 | |||
| * @arg @ref LL_EXTI_LINE_6 | |||
| * @arg @ref LL_EXTI_LINE_7 | |||
| * @arg @ref LL_EXTI_LINE_8 | |||
| * @arg @ref LL_EXTI_LINE_9 | |||
| * @arg @ref LL_EXTI_LINE_10 | |||
| * @arg @ref LL_EXTI_LINE_11 | |||
| * @arg @ref LL_EXTI_LINE_12 | |||
| * @arg @ref LL_EXTI_LINE_13 | |||
| * @arg @ref LL_EXTI_LINE_14 | |||
| * @arg @ref LL_EXTI_LINE_15 | |||
| * @arg @ref LL_EXTI_LINE_16 | |||
| * @arg @ref LL_EXTI_LINE_18 | |||
| * @arg @ref LL_EXTI_LINE_19 | |||
| * @note Please check each device line mapping for EXTI Line availability | |||
| * @retval None | |||
| */ | |||
| __STATIC_INLINE void LL_EXTI_DisableRisingTrig_0_31(uint32_t ExtiLine) | |||
| { | |||
| CLEAR_BIT(EXTI->RTSR, ExtiLine); | |||
| } | |||
| /** | |||
| * @brief Check if rising edge trigger is enabled for Lines in range 0 to 31 | |||
| * @rmtoll RTSR RTx LL_EXTI_IsEnabledRisingTrig_0_31 | |||
| * @param ExtiLine This parameter can be a combination of the following values: | |||
| * @arg @ref LL_EXTI_LINE_0 | |||
| * @arg @ref LL_EXTI_LINE_1 | |||
| * @arg @ref LL_EXTI_LINE_2 | |||
| * @arg @ref LL_EXTI_LINE_3 | |||
| * @arg @ref LL_EXTI_LINE_4 | |||
| * @arg @ref LL_EXTI_LINE_5 | |||
| * @arg @ref LL_EXTI_LINE_6 | |||
| * @arg @ref LL_EXTI_LINE_7 | |||
| * @arg @ref LL_EXTI_LINE_8 | |||
| * @arg @ref LL_EXTI_LINE_9 | |||
| * @arg @ref LL_EXTI_LINE_10 | |||
| * @arg @ref LL_EXTI_LINE_11 | |||
| * @arg @ref LL_EXTI_LINE_12 | |||
| * @arg @ref LL_EXTI_LINE_13 | |||
| * @arg @ref LL_EXTI_LINE_14 | |||
| * @arg @ref LL_EXTI_LINE_15 | |||
| * @arg @ref LL_EXTI_LINE_16 | |||
| * @arg @ref LL_EXTI_LINE_18 | |||
| * @arg @ref LL_EXTI_LINE_19 | |||
| * @note Please check each device line mapping for EXTI Line availability | |||
| * @retval State of bit (1 or 0). | |||
| */ | |||
| __STATIC_INLINE uint32_t LL_EXTI_IsEnabledRisingTrig_0_31(uint32_t ExtiLine) | |||
| { | |||
| return (READ_BIT(EXTI->RTSR, ExtiLine) == (ExtiLine)); | |||
| } | |||
| /** | |||
| * @} | |||
| */ | |||
| /** @defgroup EXTI_LL_EF_Falling_Trigger_Management Falling_Trigger_Management | |||
| * @{ | |||
| */ | |||
| /** | |||
| * @brief Enable ExtiLine Falling Edge Trigger for Lines in range 0 to 31 | |||
| * @note The configurable wakeup lines are edge-triggered. No glitch must be | |||
| * generated on these lines. If a falling edge on a configurable interrupt | |||
| * line occurs during a write operation in the EXTI_FTSR register, the | |||
| * pending bit is not set. | |||
| * Rising and falling edge triggers can be set for | |||
| * the same interrupt line. In this case, both generate a trigger | |||
| * condition. | |||
| * @rmtoll FTSR FTx LL_EXTI_EnableFallingTrig_0_31 | |||
| * @param ExtiLine This parameter can be a combination of the following values: | |||
| * @arg @ref LL_EXTI_LINE_0 | |||
| * @arg @ref LL_EXTI_LINE_1 | |||
| * @arg @ref LL_EXTI_LINE_2 | |||
| * @arg @ref LL_EXTI_LINE_3 | |||
| * @arg @ref LL_EXTI_LINE_4 | |||
| * @arg @ref LL_EXTI_LINE_5 | |||
| * @arg @ref LL_EXTI_LINE_6 | |||
| * @arg @ref LL_EXTI_LINE_7 | |||
| * @arg @ref LL_EXTI_LINE_8 | |||
| * @arg @ref LL_EXTI_LINE_9 | |||
| * @arg @ref LL_EXTI_LINE_10 | |||
| * @arg @ref LL_EXTI_LINE_11 | |||
| * @arg @ref LL_EXTI_LINE_12 | |||
| * @arg @ref LL_EXTI_LINE_13 | |||
| * @arg @ref LL_EXTI_LINE_14 | |||
| * @arg @ref LL_EXTI_LINE_15 | |||
| * @arg @ref LL_EXTI_LINE_16 | |||
| * @arg @ref LL_EXTI_LINE_18 | |||
| * @arg @ref LL_EXTI_LINE_19 | |||
| * @note Please check each device line mapping for EXTI Line availability | |||
| * @retval None | |||
| */ | |||
| __STATIC_INLINE void LL_EXTI_EnableFallingTrig_0_31(uint32_t ExtiLine) | |||
| { | |||
| SET_BIT(EXTI->FTSR, ExtiLine); | |||
| } | |||
| /** | |||
| * @brief Disable ExtiLine Falling Edge Trigger for Lines in range 0 to 31 | |||
| * @note The configurable wakeup lines are edge-triggered. No glitch must be | |||
| * generated on these lines. If a Falling edge on a configurable interrupt | |||
| * line occurs during a write operation in the EXTI_FTSR register, the | |||
| * pending bit is not set. | |||
| * Rising and falling edge triggers can be set for the same interrupt line. | |||
| * In this case, both generate a trigger condition. | |||
| * @rmtoll FTSR FTx LL_EXTI_DisableFallingTrig_0_31 | |||
| * @param ExtiLine This parameter can be a combination of the following values: | |||
| * @arg @ref LL_EXTI_LINE_0 | |||
| * @arg @ref LL_EXTI_LINE_1 | |||
| * @arg @ref LL_EXTI_LINE_2 | |||
| * @arg @ref LL_EXTI_LINE_3 | |||
| * @arg @ref LL_EXTI_LINE_4 | |||
| * @arg @ref LL_EXTI_LINE_5 | |||
| * @arg @ref LL_EXTI_LINE_6 | |||
| * @arg @ref LL_EXTI_LINE_7 | |||
| * @arg @ref LL_EXTI_LINE_8 | |||
| * @arg @ref LL_EXTI_LINE_9 | |||
| * @arg @ref LL_EXTI_LINE_10 | |||
| * @arg @ref LL_EXTI_LINE_11 | |||
| * @arg @ref LL_EXTI_LINE_12 | |||
| * @arg @ref LL_EXTI_LINE_13 | |||
| * @arg @ref LL_EXTI_LINE_14 | |||
| * @arg @ref LL_EXTI_LINE_15 | |||
| * @arg @ref LL_EXTI_LINE_16 | |||
| * @arg @ref LL_EXTI_LINE_18 | |||
| * @arg @ref LL_EXTI_LINE_19 | |||
| * @note Please check each device line mapping for EXTI Line availability | |||
| * @retval None | |||
| */ | |||
| __STATIC_INLINE void LL_EXTI_DisableFallingTrig_0_31(uint32_t ExtiLine) | |||
| { | |||
| CLEAR_BIT(EXTI->FTSR, ExtiLine); | |||
| } | |||
| /** | |||
| * @brief Check if falling edge trigger is enabled for Lines in range 0 to 31 | |||
| * @rmtoll FTSR FTx LL_EXTI_IsEnabledFallingTrig_0_31 | |||
| * @param ExtiLine This parameter can be a combination of the following values: | |||
| * @arg @ref LL_EXTI_LINE_0 | |||
| * @arg @ref LL_EXTI_LINE_1 | |||
| * @arg @ref LL_EXTI_LINE_2 | |||
| * @arg @ref LL_EXTI_LINE_3 | |||
| * @arg @ref LL_EXTI_LINE_4 | |||
| * @arg @ref LL_EXTI_LINE_5 | |||
| * @arg @ref LL_EXTI_LINE_6 | |||
| * @arg @ref LL_EXTI_LINE_7 | |||
| * @arg @ref LL_EXTI_LINE_8 | |||
| * @arg @ref LL_EXTI_LINE_9 | |||
| * @arg @ref LL_EXTI_LINE_10 | |||
| * @arg @ref LL_EXTI_LINE_11 | |||
| * @arg @ref LL_EXTI_LINE_12 | |||
| * @arg @ref LL_EXTI_LINE_13 | |||
| * @arg @ref LL_EXTI_LINE_14 | |||
| * @arg @ref LL_EXTI_LINE_15 | |||
| * @arg @ref LL_EXTI_LINE_16 | |||
| * @arg @ref LL_EXTI_LINE_18 | |||
| * @arg @ref LL_EXTI_LINE_19 | |||
| * @note Please check each device line mapping for EXTI Line availability | |||
| * @retval State of bit (1 or 0). | |||
| */ | |||
| __STATIC_INLINE uint32_t LL_EXTI_IsEnabledFallingTrig_0_31(uint32_t ExtiLine) | |||
| { | |||
| return (READ_BIT(EXTI->FTSR, ExtiLine) == (ExtiLine)); | |||
| } | |||
| /** | |||
| * @} | |||
| */ | |||
| /** @defgroup EXTI_LL_EF_Software_Interrupt_Management Software_Interrupt_Management | |||
| * @{ | |||
| */ | |||
| /** | |||
| * @brief Generate a software Interrupt Event for Lines in range 0 to 31 | |||
| * @note If the interrupt is enabled on this line in the EXTI_IMR, writing a 1 to | |||
| * this bit when it is at '0' sets the corresponding pending bit in EXTI_PR | |||
| * resulting in an interrupt request generation. | |||
| * This bit is cleared by clearing the corresponding bit in the EXTI_PR | |||
| * register (by writing a 1 into the bit) | |||
| * @rmtoll SWIER SWIx LL_EXTI_GenerateSWI_0_31 | |||
| * @param ExtiLine This parameter can be a combination of the following values: | |||
| * @arg @ref LL_EXTI_LINE_0 | |||
| * @arg @ref LL_EXTI_LINE_1 | |||
| * @arg @ref LL_EXTI_LINE_2 | |||
| * @arg @ref LL_EXTI_LINE_3 | |||
| * @arg @ref LL_EXTI_LINE_4 | |||
| * @arg @ref LL_EXTI_LINE_5 | |||
| * @arg @ref LL_EXTI_LINE_6 | |||
| * @arg @ref LL_EXTI_LINE_7 | |||
| * @arg @ref LL_EXTI_LINE_8 | |||
| * @arg @ref LL_EXTI_LINE_9 | |||
| * @arg @ref LL_EXTI_LINE_10 | |||
| * @arg @ref LL_EXTI_LINE_11 | |||
| * @arg @ref LL_EXTI_LINE_12 | |||
| * @arg @ref LL_EXTI_LINE_13 | |||
| * @arg @ref LL_EXTI_LINE_14 | |||
| * @arg @ref LL_EXTI_LINE_15 | |||
| * @arg @ref LL_EXTI_LINE_16 | |||
| * @arg @ref LL_EXTI_LINE_18 | |||
| * @arg @ref LL_EXTI_LINE_19 | |||
| * @note Please check each device line mapping for EXTI Line availability | |||
| * @retval None | |||
| */ | |||
| __STATIC_INLINE void LL_EXTI_GenerateSWI_0_31(uint32_t ExtiLine) | |||
| { | |||
| SET_BIT(EXTI->SWIER, ExtiLine); | |||
| } | |||
| /** | |||
| * @} | |||
| */ | |||
| /** @defgroup EXTI_LL_EF_Flag_Management Flag_Management | |||
| * @{ | |||
| */ | |||
| /** | |||
| * @brief Check if the ExtLine Flag is set or not for Lines in range 0 to 31 | |||
| * @note This bit is set when the selected edge event arrives on the interrupt | |||
| * line. This bit is cleared by writing a 1 to the bit. | |||
| * @rmtoll PR PIFx LL_EXTI_IsActiveFlag_0_31 | |||
| * @param ExtiLine This parameter can be a combination of the following values: | |||
| * @arg @ref LL_EXTI_LINE_0 | |||
| * @arg @ref LL_EXTI_LINE_1 | |||
| * @arg @ref LL_EXTI_LINE_2 | |||
| * @arg @ref LL_EXTI_LINE_3 | |||
| * @arg @ref LL_EXTI_LINE_4 | |||
| * @arg @ref LL_EXTI_LINE_5 | |||
| * @arg @ref LL_EXTI_LINE_6 | |||
| * @arg @ref LL_EXTI_LINE_7 | |||
| * @arg @ref LL_EXTI_LINE_8 | |||
| * @arg @ref LL_EXTI_LINE_9 | |||
| * @arg @ref LL_EXTI_LINE_10 | |||
| * @arg @ref LL_EXTI_LINE_11 | |||
| * @arg @ref LL_EXTI_LINE_12 | |||
| * @arg @ref LL_EXTI_LINE_13 | |||
| * @arg @ref LL_EXTI_LINE_14 | |||
| * @arg @ref LL_EXTI_LINE_15 | |||
| * @arg @ref LL_EXTI_LINE_16 | |||
| * @arg @ref LL_EXTI_LINE_18 | |||
| * @arg @ref LL_EXTI_LINE_19 | |||
| * @note Please check each device line mapping for EXTI Line availability | |||
| * @retval State of bit (1 or 0). | |||
| */ | |||
| __STATIC_INLINE uint32_t LL_EXTI_IsActiveFlag_0_31(uint32_t ExtiLine) | |||
| { | |||
| return (READ_BIT(EXTI->PR, ExtiLine) == (ExtiLine)); | |||
| } | |||
| /** | |||
| * @brief Read ExtLine Combination Flag for Lines in range 0 to 31 | |||
| * @note This bit is set when the selected edge event arrives on the interrupt | |||
| * line. This bit is cleared by writing a 1 to the bit. | |||
| * @rmtoll PR PIFx LL_EXTI_ReadFlag_0_31 | |||
| * @param ExtiLine This parameter can be a combination of the following values: | |||
| * @arg @ref LL_EXTI_LINE_0 | |||
| * @arg @ref LL_EXTI_LINE_1 | |||
| * @arg @ref LL_EXTI_LINE_2 | |||
| * @arg @ref LL_EXTI_LINE_3 | |||
| * @arg @ref LL_EXTI_LINE_4 | |||
| * @arg @ref LL_EXTI_LINE_5 | |||
| * @arg @ref LL_EXTI_LINE_6 | |||
| * @arg @ref LL_EXTI_LINE_7 | |||
| * @arg @ref LL_EXTI_LINE_8 | |||
| * @arg @ref LL_EXTI_LINE_9 | |||
| * @arg @ref LL_EXTI_LINE_10 | |||
| * @arg @ref LL_EXTI_LINE_11 | |||
| * @arg @ref LL_EXTI_LINE_12 | |||
| * @arg @ref LL_EXTI_LINE_13 | |||
| * @arg @ref LL_EXTI_LINE_14 | |||
| * @arg @ref LL_EXTI_LINE_15 | |||
| * @arg @ref LL_EXTI_LINE_16 | |||
| * @arg @ref LL_EXTI_LINE_18 | |||
| * @arg @ref LL_EXTI_LINE_19 | |||
| * @note Please check each device line mapping for EXTI Line availability | |||
| * @retval @note This bit is set when the selected edge event arrives on the interrupt | |||
| */ | |||
| __STATIC_INLINE uint32_t LL_EXTI_ReadFlag_0_31(uint32_t ExtiLine) | |||
| { | |||
| return (uint32_t)(READ_BIT(EXTI->PR, ExtiLine)); | |||
| } | |||
| /** | |||
| * @brief Clear ExtLine Flags for Lines in range 0 to 31 | |||
| * @note This bit is set when the selected edge event arrives on the interrupt | |||
| * line. This bit is cleared by writing a 1 to the bit. | |||
| * @rmtoll PR PIFx LL_EXTI_ClearFlag_0_31 | |||
| * @param ExtiLine This parameter can be a combination of the following values: | |||
| * @arg @ref LL_EXTI_LINE_0 | |||
| * @arg @ref LL_EXTI_LINE_1 | |||
| * @arg @ref LL_EXTI_LINE_2 | |||
| * @arg @ref LL_EXTI_LINE_3 | |||
| * @arg @ref LL_EXTI_LINE_4 | |||
| * @arg @ref LL_EXTI_LINE_5 | |||
| * @arg @ref LL_EXTI_LINE_6 | |||
| * @arg @ref LL_EXTI_LINE_7 | |||
| * @arg @ref LL_EXTI_LINE_8 | |||
| * @arg @ref LL_EXTI_LINE_9 | |||
| * @arg @ref LL_EXTI_LINE_10 | |||
| * @arg @ref LL_EXTI_LINE_11 | |||
| * @arg @ref LL_EXTI_LINE_12 | |||
| * @arg @ref LL_EXTI_LINE_13 | |||
| * @arg @ref LL_EXTI_LINE_14 | |||
| * @arg @ref LL_EXTI_LINE_15 | |||
| * @arg @ref LL_EXTI_LINE_16 | |||
| * @arg @ref LL_EXTI_LINE_18 | |||
| * @arg @ref LL_EXTI_LINE_19 | |||
| * @note Please check each device line mapping for EXTI Line availability | |||
| * @retval None | |||
| */ | |||
| __STATIC_INLINE void LL_EXTI_ClearFlag_0_31(uint32_t ExtiLine) | |||
| { | |||
| WRITE_REG(EXTI->PR, ExtiLine); | |||
| } | |||
| /** | |||
| * @} | |||
| */ | |||
| #if defined(USE_FULL_LL_DRIVER) | |||
| /** @defgroup EXTI_LL_EF_Init Initialization and de-initialization functions | |||
| * @{ | |||
| */ | |||
| uint32_t LL_EXTI_Init(LL_EXTI_InitTypeDef *EXTI_InitStruct); | |||
| uint32_t LL_EXTI_DeInit(void); | |||
| void LL_EXTI_StructInit(LL_EXTI_InitTypeDef *EXTI_InitStruct); | |||
| /** | |||
| * @} | |||
| */ | |||
| #endif /* USE_FULL_LL_DRIVER */ | |||
| /** | |||
| * @} | |||
| */ | |||
| /** | |||
| * @} | |||
| */ | |||
| #endif /* EXTI */ | |||
| /** | |||
| * @} | |||
| */ | |||
| #ifdef __cplusplus | |||
| } | |||
| #endif | |||
| #endif /* STM32F1xx_LL_EXTI_H */ | |||
| @ -0,0 +1,437 @@ | |||
| /** | |||
| ****************************************************************************** | |||
| * @file stm32f1xx_ll_pwr.h | |||
| * @author MCD Application Team | |||
| * @brief Header file of PWR LL module. | |||
| ****************************************************************************** | |||
| * @attention | |||
| * | |||
| * Copyright (c) 2016 STMicroelectronics. | |||
| * All rights reserved. | |||
| * | |||
| * This software is licensed under terms that can be found in the LICENSE file | |||
| * in the root directory of this software component. | |||
| * If no LICENSE file comes with this software, it is provided AS-IS. | |||
| * | |||
| ****************************************************************************** | |||
| */ | |||
| /* Define to prevent recursive inclusion -------------------------------------*/ | |||
| #ifndef __STM32F1xx_LL_PWR_H | |||
| #define __STM32F1xx_LL_PWR_H | |||
| #ifdef __cplusplus | |||
| extern "C" { | |||
| #endif | |||
| /* Includes ------------------------------------------------------------------*/ | |||
| #include "stm32f1xx.h" | |||
| /** @addtogroup STM32F1xx_LL_Driver | |||
| * @{ | |||
| */ | |||
| #if defined(PWR) | |||
| /** @defgroup PWR_LL PWR | |||
| * @{ | |||
| */ | |||
| /* Private types -------------------------------------------------------------*/ | |||
| /* Private variables ---------------------------------------------------------*/ | |||
| /* Private constants ---------------------------------------------------------*/ | |||
| /* Private macros ------------------------------------------------------------*/ | |||
| /* Exported types ------------------------------------------------------------*/ | |||
| /* Exported constants --------------------------------------------------------*/ | |||
| /** @defgroup PWR_LL_Exported_Constants PWR Exported Constants | |||
| * @{ | |||
| */ | |||
| /** @defgroup PWR_LL_EC_CLEAR_FLAG Clear Flags Defines | |||
| * @brief Flags defines which can be used with LL_PWR_WriteReg function | |||
| * @{ | |||
| */ | |||
| #define LL_PWR_CR_CSBF PWR_CR_CSBF /*!< Clear standby flag */ | |||
| #define LL_PWR_CR_CWUF PWR_CR_CWUF /*!< Clear wakeup flag */ | |||
| /** | |||
| * @} | |||
| */ | |||
| /** @defgroup PWR_LL_EC_GET_FLAG Get Flags Defines | |||
| * @brief Flags defines which can be used with LL_PWR_ReadReg function | |||
| * @{ | |||
| */ | |||
| #define LL_PWR_CSR_WUF PWR_CSR_WUF /*!< Wakeup flag */ | |||
| #define LL_PWR_CSR_SBF PWR_CSR_SBF /*!< Standby flag */ | |||
| #define LL_PWR_CSR_PVDO PWR_CSR_PVDO /*!< Power voltage detector output flag */ | |||
| #define LL_PWR_CSR_EWUP1 PWR_CSR_EWUP /*!< Enable WKUP pin 1 */ | |||
| /** | |||
| * @} | |||
| */ | |||
| /** @defgroup PWR_LL_EC_MODE_PWR Mode Power | |||
| * @{ | |||
| */ | |||
| #define LL_PWR_MODE_STOP_MAINREGU 0x00000000U /*!< Enter Stop mode when the CPU enters deepsleep */ | |||
| #define LL_PWR_MODE_STOP_LPREGU (PWR_CR_LPDS) /*!< Enter Stop mode (with low power Regulator ON) when the CPU enters deepsleep */ | |||
| #define LL_PWR_MODE_STANDBY (PWR_CR_PDDS) /*!< Enter Standby mode when the CPU enters deepsleep */ | |||
| /** | |||
| * @} | |||
| */ | |||
| /** @defgroup PWR_LL_EC_REGU_MODE_DS_MODE Regulator Mode In Deep Sleep Mode | |||
| * @{ | |||
| */ | |||
| #define LL_PWR_REGU_DSMODE_MAIN 0x00000000U /*!< Voltage Regulator in main mode during deepsleep mode */ | |||
| #define LL_PWR_REGU_DSMODE_LOW_POWER (PWR_CR_LPDS) /*!< Voltage Regulator in low-power mode during deepsleep mode */ | |||
| /** | |||
| * @} | |||
| */ | |||
| /** @defgroup PWR_LL_EC_PVDLEVEL Power Voltage Detector Level | |||
| * @{ | |||
| */ | |||
| #define LL_PWR_PVDLEVEL_0 (PWR_CR_PLS_LEV0) /*!< Voltage threshold detected by PVD 2.2 V */ | |||
| #define LL_PWR_PVDLEVEL_1 (PWR_CR_PLS_LEV1) /*!< Voltage threshold detected by PVD 2.3 V */ | |||
| #define LL_PWR_PVDLEVEL_2 (PWR_CR_PLS_LEV2) /*!< Voltage threshold detected by PVD 2.4 V */ | |||
| #define LL_PWR_PVDLEVEL_3 (PWR_CR_PLS_LEV3) /*!< Voltage threshold detected by PVD 2.5 V */ | |||
| #define LL_PWR_PVDLEVEL_4 (PWR_CR_PLS_LEV4) /*!< Voltage threshold detected by PVD 2.6 V */ | |||
| #define LL_PWR_PVDLEVEL_5 (PWR_CR_PLS_LEV5) /*!< Voltage threshold detected by PVD 2.7 V */ | |||
| #define LL_PWR_PVDLEVEL_6 (PWR_CR_PLS_LEV6) /*!< Voltage threshold detected by PVD 2.8 V */ | |||
| #define LL_PWR_PVDLEVEL_7 (PWR_CR_PLS_LEV7) /*!< Voltage threshold detected by PVD 2.9 V */ | |||
| /** | |||
| * @} | |||
| */ | |||
| /** @defgroup PWR_LL_EC_WAKEUP_PIN Wakeup Pins | |||
| * @{ | |||
| */ | |||
| #define LL_PWR_WAKEUP_PIN1 (PWR_CSR_EWUP) /*!< WKUP pin 1 : PA0 */ | |||
| /** | |||
| * @} | |||
| */ | |||
| /** | |||
| * @} | |||
| */ | |||
| /* Exported macro ------------------------------------------------------------*/ | |||
| /** @defgroup PWR_LL_Exported_Macros PWR Exported Macros | |||
| * @{ | |||
| */ | |||
| /** @defgroup PWR_LL_EM_WRITE_READ Common write and read registers Macros | |||
| * @{ | |||
| */ | |||
| /** | |||
| * @brief Write a value in PWR register | |||
| * @param __REG__ Register to be written | |||
| * @param __VALUE__ Value to be written in the register | |||
| * @retval None | |||
| */ | |||
| #define LL_PWR_WriteReg(__REG__, __VALUE__) WRITE_REG(PWR->__REG__, (__VALUE__)) | |||
| /** | |||
| * @brief Read a value in PWR register | |||
| * @param __REG__ Register to be read | |||
| * @retval Register value | |||
| */ | |||
| #define LL_PWR_ReadReg(__REG__) READ_REG(PWR->__REG__) | |||
| /** | |||
| * @} | |||
| */ | |||
| /** | |||
| * @} | |||
| */ | |||
| /* Exported functions --------------------------------------------------------*/ | |||
| /** @defgroup PWR_LL_Exported_Functions PWR Exported Functions | |||
| * @{ | |||
| */ | |||
| /** @defgroup PWR_LL_EF_Configuration Configuration | |||
| * @{ | |||
| */ | |||
| /** | |||
| * @brief Enable access to the backup domain | |||
| * @rmtoll CR DBP LL_PWR_EnableBkUpAccess | |||
| * @retval None | |||
| */ | |||
| __STATIC_INLINE void LL_PWR_EnableBkUpAccess(void) | |||
| { | |||
| SET_BIT(PWR->CR, PWR_CR_DBP); | |||
| } | |||
| /** | |||
| * @brief Disable access to the backup domain | |||
| * @rmtoll CR DBP LL_PWR_DisableBkUpAccess | |||
| * @retval None | |||
| */ | |||
| __STATIC_INLINE void LL_PWR_DisableBkUpAccess(void) | |||
| { | |||
| CLEAR_BIT(PWR->CR, PWR_CR_DBP); | |||
| } | |||
| /** | |||
| * @brief Check if the backup domain is enabled | |||
| * @rmtoll CR DBP LL_PWR_IsEnabledBkUpAccess | |||
| * @retval State of bit (1 or 0). | |||
| */ | |||
| __STATIC_INLINE uint32_t LL_PWR_IsEnabledBkUpAccess(void) | |||
| { | |||
| return (READ_BIT(PWR->CR, PWR_CR_DBP) == (PWR_CR_DBP)); | |||
| } | |||
| /** | |||
| * @brief Set voltage Regulator mode during deep sleep mode | |||
| * @rmtoll CR LPDS LL_PWR_SetRegulModeDS | |||
| * @param RegulMode This parameter can be one of the following values: | |||
| * @arg @ref LL_PWR_REGU_DSMODE_MAIN | |||
| * @arg @ref LL_PWR_REGU_DSMODE_LOW_POWER | |||
| * @retval None | |||
| */ | |||
| __STATIC_INLINE void LL_PWR_SetRegulModeDS(uint32_t RegulMode) | |||
| { | |||
| MODIFY_REG(PWR->CR, PWR_CR_LPDS, RegulMode); | |||
| } | |||
| /** | |||
| * @brief Get voltage Regulator mode during deep sleep mode | |||
| * @rmtoll CR LPDS LL_PWR_GetRegulModeDS | |||
| * @retval Returned value can be one of the following values: | |||
| * @arg @ref LL_PWR_REGU_DSMODE_MAIN | |||
| * @arg @ref LL_PWR_REGU_DSMODE_LOW_POWER | |||
| */ | |||
| __STATIC_INLINE uint32_t LL_PWR_GetRegulModeDS(void) | |||
| { | |||
| return (uint32_t)(READ_BIT(PWR->CR, PWR_CR_LPDS)); | |||
| } | |||
| /** | |||
| * @brief Set Power Down mode when CPU enters deepsleep | |||
| * @rmtoll CR PDDS LL_PWR_SetPowerMode\n | |||
| * @rmtoll CR LPDS LL_PWR_SetPowerMode | |||
| * @param PDMode This parameter can be one of the following values: | |||
| * @arg @ref LL_PWR_MODE_STOP_MAINREGU | |||
| * @arg @ref LL_PWR_MODE_STOP_LPREGU | |||
| * @arg @ref LL_PWR_MODE_STANDBY | |||
| * @retval None | |||
| */ | |||
| __STATIC_INLINE void LL_PWR_SetPowerMode(uint32_t PDMode) | |||
| { | |||
| MODIFY_REG(PWR->CR, (PWR_CR_PDDS| PWR_CR_LPDS), PDMode); | |||
| } | |||
| /** | |||
| * @brief Get Power Down mode when CPU enters deepsleep | |||
| * @rmtoll CR PDDS LL_PWR_GetPowerMode\n | |||
| * @rmtoll CR LPDS LL_PWR_GetPowerMode | |||
| * @retval Returned value can be one of the following values: | |||
| * @arg @ref LL_PWR_MODE_STOP_MAINREGU | |||
| * @arg @ref LL_PWR_MODE_STOP_LPREGU | |||
| * @arg @ref LL_PWR_MODE_STANDBY | |||
| */ | |||
| __STATIC_INLINE uint32_t LL_PWR_GetPowerMode(void) | |||
| { | |||
| return (uint32_t)(READ_BIT(PWR->CR, (PWR_CR_PDDS| PWR_CR_LPDS))); | |||
| } | |||
| /** | |||
| * @brief Configure the voltage threshold detected by the Power Voltage Detector | |||
| * @rmtoll CR PLS LL_PWR_SetPVDLevel | |||
| * @param PVDLevel This parameter can be one of the following values: | |||
| * @arg @ref LL_PWR_PVDLEVEL_0 | |||
| * @arg @ref LL_PWR_PVDLEVEL_1 | |||
| * @arg @ref LL_PWR_PVDLEVEL_2 | |||
| * @arg @ref LL_PWR_PVDLEVEL_3 | |||
| * @arg @ref LL_PWR_PVDLEVEL_4 | |||
| * @arg @ref LL_PWR_PVDLEVEL_5 | |||
| * @arg @ref LL_PWR_PVDLEVEL_6 | |||
| * @arg @ref LL_PWR_PVDLEVEL_7 | |||
| * @retval None | |||
| */ | |||
| __STATIC_INLINE void LL_PWR_SetPVDLevel(uint32_t PVDLevel) | |||
| { | |||
| MODIFY_REG(PWR->CR, PWR_CR_PLS, PVDLevel); | |||
| } | |||
| /** | |||
| * @brief Get the voltage threshold detection | |||
| * @rmtoll CR PLS LL_PWR_GetPVDLevel | |||
| * @retval Returned value can be one of the following values: | |||
| * @arg @ref LL_PWR_PVDLEVEL_0 | |||
| * @arg @ref LL_PWR_PVDLEVEL_1 | |||
| * @arg @ref LL_PWR_PVDLEVEL_2 | |||
| * @arg @ref LL_PWR_PVDLEVEL_3 | |||
| * @arg @ref LL_PWR_PVDLEVEL_4 | |||
| * @arg @ref LL_PWR_PVDLEVEL_5 | |||
| * @arg @ref LL_PWR_PVDLEVEL_6 | |||
| * @arg @ref LL_PWR_PVDLEVEL_7 | |||
| */ | |||
| __STATIC_INLINE uint32_t LL_PWR_GetPVDLevel(void) | |||
| { | |||
| return (uint32_t)(READ_BIT(PWR->CR, PWR_CR_PLS)); | |||
| } | |||
| /** | |||
| * @brief Enable Power Voltage Detector | |||
| * @rmtoll CR PVDE LL_PWR_EnablePVD | |||
| * @retval None | |||
| */ | |||
| __STATIC_INLINE void LL_PWR_EnablePVD(void) | |||
| { | |||
| SET_BIT(PWR->CR, PWR_CR_PVDE); | |||
| } | |||
| /** | |||
| * @brief Disable Power Voltage Detector | |||
| * @rmtoll CR PVDE LL_PWR_DisablePVD | |||
| * @retval None | |||
| */ | |||
| __STATIC_INLINE void LL_PWR_DisablePVD(void) | |||
| { | |||
| CLEAR_BIT(PWR->CR, PWR_CR_PVDE); | |||
| } | |||
| /** | |||
| * @brief Check if Power Voltage Detector is enabled | |||
| * @rmtoll CR PVDE LL_PWR_IsEnabledPVD | |||
| * @retval State of bit (1 or 0). | |||
| */ | |||
| __STATIC_INLINE uint32_t LL_PWR_IsEnabledPVD(void) | |||
| { | |||
| return (READ_BIT(PWR->CR, PWR_CR_PVDE) == (PWR_CR_PVDE)); | |||
| } | |||
| /** | |||
| * @brief Enable the WakeUp PINx functionality | |||
| * @rmtoll CSR EWUP LL_PWR_EnableWakeUpPin | |||
| * @param WakeUpPin This parameter can be one of the following values: | |||
| * @arg @ref LL_PWR_WAKEUP_PIN1 | |||
| * @retval None | |||
| */ | |||
| __STATIC_INLINE void LL_PWR_EnableWakeUpPin(uint32_t WakeUpPin) | |||
| { | |||
| SET_BIT(PWR->CSR, WakeUpPin); | |||
| } | |||
| /** | |||
| * @brief Disable the WakeUp PINx functionality | |||
| * @rmtoll CSR EWUP LL_PWR_DisableWakeUpPin | |||
| * @param WakeUpPin This parameter can be one of the following values: | |||
| * @arg @ref LL_PWR_WAKEUP_PIN1 | |||
| * @retval None | |||
| */ | |||
| __STATIC_INLINE void LL_PWR_DisableWakeUpPin(uint32_t WakeUpPin) | |||
| { | |||
| CLEAR_BIT(PWR->CSR, WakeUpPin); | |||
| } | |||
| /** | |||
| * @brief Check if the WakeUp PINx functionality is enabled | |||
| * @rmtoll CSR EWUP LL_PWR_IsEnabledWakeUpPin | |||
| * @param WakeUpPin This parameter can be one of the following values: | |||
| * @arg @ref LL_PWR_WAKEUP_PIN1 | |||
| * @retval State of bit (1 or 0). | |||
| */ | |||
| __STATIC_INLINE uint32_t LL_PWR_IsEnabledWakeUpPin(uint32_t WakeUpPin) | |||
| { | |||
| return (READ_BIT(PWR->CSR, WakeUpPin) == (WakeUpPin)); | |||
| } | |||
| /** | |||
| * @} | |||
| */ | |||
| /** @defgroup PWR_LL_EF_FLAG_Management FLAG_Management | |||
| * @{ | |||
| */ | |||
| /** | |||
| * @brief Get Wake-up Flag | |||
| * @rmtoll CSR WUF LL_PWR_IsActiveFlag_WU | |||
| * @retval State of bit (1 or 0). | |||
| */ | |||
| __STATIC_INLINE uint32_t LL_PWR_IsActiveFlag_WU(void) | |||
| { | |||
| return (READ_BIT(PWR->CSR, PWR_CSR_WUF) == (PWR_CSR_WUF)); | |||
| } | |||
| /** | |||
| * @brief Get Standby Flag | |||
| * @rmtoll CSR SBF LL_PWR_IsActiveFlag_SB | |||
| * @retval State of bit (1 or 0). | |||
| */ | |||
| __STATIC_INLINE uint32_t LL_PWR_IsActiveFlag_SB(void) | |||
| { | |||
| return (READ_BIT(PWR->CSR, PWR_CSR_SBF) == (PWR_CSR_SBF)); | |||
| } | |||
| /** | |||
| * @brief Indicate whether VDD voltage is below the selected PVD threshold | |||
| * @rmtoll CSR PVDO LL_PWR_IsActiveFlag_PVDO | |||
| * @retval State of bit (1 or 0). | |||
| */ | |||
| __STATIC_INLINE uint32_t LL_PWR_IsActiveFlag_PVDO(void) | |||
| { | |||
| return (READ_BIT(PWR->CSR, PWR_CSR_PVDO) == (PWR_CSR_PVDO)); | |||
| } | |||
| /** | |||
| * @brief Clear Standby Flag | |||
| * @rmtoll CR CSBF LL_PWR_ClearFlag_SB | |||
| * @retval None | |||
| */ | |||
| __STATIC_INLINE void LL_PWR_ClearFlag_SB(void) | |||
| { | |||
| SET_BIT(PWR->CR, PWR_CR_CSBF); | |||
| } | |||
| /** | |||
| * @brief Clear Wake-up Flags | |||
| * @rmtoll CR CWUF LL_PWR_ClearFlag_WU | |||
| * @retval None | |||
| */ | |||
| __STATIC_INLINE void LL_PWR_ClearFlag_WU(void) | |||
| { | |||
| SET_BIT(PWR->CR, PWR_CR_CWUF); | |||
| } | |||
| /** | |||
| * @} | |||
| */ | |||
| #if defined(USE_FULL_LL_DRIVER) | |||
| /** @defgroup PWR_LL_EF_Init De-initialization function | |||
| * @{ | |||
| */ | |||
| ErrorStatus LL_PWR_DeInit(void); | |||
| /** | |||
| * @} | |||
| */ | |||
| #endif /* USE_FULL_LL_DRIVER */ | |||
| /** | |||
| * @} | |||
| */ | |||
| /** | |||
| * @} | |||
| */ | |||
| #endif /* defined(PWR) */ | |||
| /** | |||
| * @} | |||
| */ | |||
| #ifdef __cplusplus | |||
| } | |||
| #endif | |||
| #endif /* __STM32F1xx_LL_PWR_H */ | |||
| @ -0,0 +1,575 @@ | |||
| /** | |||
| ****************************************************************************** | |||
| * @file stm32f1xx_ll_system.h | |||
| * @author MCD Application Team | |||
| * @brief Header file of SYSTEM LL module. | |||
| * | |||
| ****************************************************************************** | |||
| * @attention | |||
| * | |||
| * Copyright (c) 2016 STMicroelectronics. | |||
| * All rights reserved. | |||
| * | |||
| * This software is licensed under terms that can be found in the LICENSE file | |||
| * in the root directory of this software component. | |||
| * If no LICENSE file comes with this software, it is provided AS-IS. | |||
| * | |||
| ****************************************************************************** | |||
| @verbatim | |||
| ============================================================================== | |||
| ##### How to use this driver ##### | |||
| ============================================================================== | |||
| [..] | |||
| The LL SYSTEM driver contains a set of generic APIs that can be | |||
| used by user: | |||
| (+) Some of the FLASH features need to be handled in the SYSTEM file. | |||
| (+) Access to DBGCMU registers | |||
| (+) Access to SYSCFG registers | |||
| @endverbatim | |||
| ****************************************************************************** | |||
| */ | |||
| /* Define to prevent recursive inclusion -------------------------------------*/ | |||
| #ifndef __STM32F1xx_LL_SYSTEM_H | |||
| #define __STM32F1xx_LL_SYSTEM_H | |||
| #ifdef __cplusplus | |||
| extern "C" { | |||
| #endif | |||
| /* Includes ------------------------------------------------------------------*/ | |||
| #include "stm32f1xx.h" | |||
| /** @addtogroup STM32F1xx_LL_Driver | |||
| * @{ | |||
| */ | |||
| #if defined (FLASH) || defined (DBGMCU) | |||
| /** @defgroup SYSTEM_LL SYSTEM | |||
| * @{ | |||
| */ | |||
| /* Private types -------------------------------------------------------------*/ | |||
| /* Private variables ---------------------------------------------------------*/ | |||
| /* Private constants ---------------------------------------------------------*/ | |||
| /** @defgroup SYSTEM_LL_Private_Constants SYSTEM Private Constants | |||
| * @{ | |||
| */ | |||
| /** | |||
| * @} | |||
| */ | |||
| /* Private macros ------------------------------------------------------------*/ | |||
| /* Exported types ------------------------------------------------------------*/ | |||
| /* Exported constants --------------------------------------------------------*/ | |||
| /** @defgroup SYSTEM_LL_Exported_Constants SYSTEM Exported Constants | |||
| * @{ | |||
| */ | |||
| /** @defgroup SYSTEM_LL_EC_TRACE DBGMCU TRACE Pin Assignment | |||
| * @{ | |||
| */ | |||
| #define LL_DBGMCU_TRACE_NONE 0x00000000U /*!< TRACE pins not assigned (default state) */ | |||
| #define LL_DBGMCU_TRACE_ASYNCH DBGMCU_CR_TRACE_IOEN /*!< TRACE pin assignment for Asynchronous Mode */ | |||
| #define LL_DBGMCU_TRACE_SYNCH_SIZE1 (DBGMCU_CR_TRACE_IOEN | DBGMCU_CR_TRACE_MODE_0) /*!< TRACE pin assignment for Synchronous Mode with a TRACEDATA size of 1 */ | |||
| #define LL_DBGMCU_TRACE_SYNCH_SIZE2 (DBGMCU_CR_TRACE_IOEN | DBGMCU_CR_TRACE_MODE_1) /*!< TRACE pin assignment for Synchronous Mode with a TRACEDATA size of 2 */ | |||
| #define LL_DBGMCU_TRACE_SYNCH_SIZE4 (DBGMCU_CR_TRACE_IOEN | DBGMCU_CR_TRACE_MODE) /*!< TRACE pin assignment for Synchronous Mode with a TRACEDATA size of 4 */ | |||
| /** | |||
| * @} | |||
| */ | |||
| /** @defgroup SYSTEM_LL_EC_APB1_GRP1_STOP_IP DBGMCU APB1 GRP1 STOP IP | |||
| * @{ | |||
| */ | |||
| #define LL_DBGMCU_APB1_GRP1_TIM2_STOP DBGMCU_CR_DBG_TIM2_STOP /*!< TIM2 counter stopped when core is halted */ | |||
| #define LL_DBGMCU_APB1_GRP1_TIM3_STOP DBGMCU_CR_DBG_TIM3_STOP /*!< TIM3 counter stopped when core is halted */ | |||
| #define LL_DBGMCU_APB1_GRP1_TIM4_STOP DBGMCU_CR_DBG_TIM4_STOP /*!< TIM4 counter stopped when core is halted */ | |||
| #if defined(DBGMCU_CR_DBG_TIM5_STOP) | |||
| #define LL_DBGMCU_APB1_GRP1_TIM5_STOP DBGMCU_CR_DBG_TIM5_STOP /*!< TIM5 counter stopped when core is halted */ | |||
| #endif /* DBGMCU_CR_DBG_TIM5_STOP */ | |||
| #if defined(DBGMCU_CR_DBG_TIM6_STOP) | |||
| #define LL_DBGMCU_APB1_GRP1_TIM6_STOP DBGMCU_CR_DBG_TIM6_STOP /*!< TIM6 counter stopped when core is halted */ | |||
| #endif /* DBGMCU_CR_DBG_TIM6_STOP */ | |||
| #if defined(DBGMCU_CR_DBG_TIM7_STOP) | |||
| #define LL_DBGMCU_APB1_GRP1_TIM7_STOP DBGMCU_CR_DBG_TIM7_STOP /*!< TIM7 counter stopped when core is halted */ | |||
| #endif /* DBGMCU_CR_DBG_TIM7_STOP */ | |||
| #if defined(DBGMCU_CR_DBG_TIM12_STOP) | |||
| #define LL_DBGMCU_APB1_GRP1_TIM12_STOP DBGMCU_CR_DBG_TIM12_STOP /*!< TIM12 counter stopped when core is halted */ | |||
| #endif /* DBGMCU_CR_DBG_TIM12_STOP */ | |||
| #if defined(DBGMCU_CR_DBG_TIM13_STOP) | |||
| #define LL_DBGMCU_APB1_GRP1_TIM13_STOP DBGMCU_CR_DBG_TIM13_STOP /*!< TIM13 counter stopped when core is halted */ | |||
| #endif /* DBGMCU_CR_DBG_TIM13_STOP */ | |||
| #if defined(DBGMCU_CR_DBG_TIM14_STOP) | |||
| #define LL_DBGMCU_APB1_GRP1_TIM14_STOP DBGMCU_CR_DBG_TIM14_STOP /*!< TIM14 counter stopped when core is halted */ | |||
| #endif /* DBGMCU_CR_DBG_TIM14_STOP */ | |||
| #define LL_DBGMCU_APB1_GRP1_WWDG_STOP DBGMCU_CR_DBG_WWDG_STOP /*!< Debug Window Watchdog stopped when Core is halted */ | |||
| #define LL_DBGMCU_APB1_GRP1_IWDG_STOP DBGMCU_CR_DBG_IWDG_STOP /*!< Debug Independent Watchdog stopped when Core is halted */ | |||
| #define LL_DBGMCU_APB1_GRP1_I2C1_STOP DBGMCU_CR_DBG_I2C1_SMBUS_TIMEOUT /*!< I2C1 SMBUS timeout mode stopped when Core is halted */ | |||
| #if defined(DBGMCU_CR_DBG_I2C2_SMBUS_TIMEOUT) | |||
| #define LL_DBGMCU_APB1_GRP1_I2C2_STOP DBGMCU_CR_DBG_I2C2_SMBUS_TIMEOUT /*!< I2C2 SMBUS timeout mode stopped when Core is halted */ | |||
| #endif /* DBGMCU_CR_DBG_I2C2_SMBUS_TIMEOUT */ | |||
| #if defined(DBGMCU_CR_DBG_CAN1_STOP) | |||
| #define LL_DBGMCU_APB1_GRP1_CAN1_STOP DBGMCU_CR_DBG_CAN1_STOP /*!< CAN1 debug stopped when Core is halted */ | |||
| #endif /* DBGMCU_CR_DBG_CAN1_STOP */ | |||
| #if defined(DBGMCU_CR_DBG_CAN2_STOP) | |||
| #define LL_DBGMCU_APB1_GRP1_CAN2_STOP DBGMCU_CR_DBG_CAN2_STOP /*!< CAN2 debug stopped when Core is halted */ | |||
| #endif /* DBGMCU_CR_DBG_CAN2_STOP */ | |||
| /** | |||
| * @} | |||
| */ | |||
| /** @defgroup SYSTEM_LL_EC_APB2_GRP1_STOP_IP DBGMCU APB2 GRP1 STOP IP | |||
| * @{ | |||
| */ | |||
| #define LL_DBGMCU_APB2_GRP1_TIM1_STOP DBGMCU_CR_DBG_TIM1_STOP /*!< TIM1 counter stopped when core is halted */ | |||
| #if defined(DBGMCU_CR_DBG_TIM8_STOP) | |||
| #define LL_DBGMCU_APB2_GRP1_TIM8_STOP DBGMCU_CR_DBG_TIM8_STOP /*!< TIM8 counter stopped when core is halted */ | |||
| #endif /* DBGMCU_CR_DBG_CAN1_STOP */ | |||
| #if defined(DBGMCU_CR_DBG_TIM9_STOP) | |||
| #define LL_DBGMCU_APB2_GRP1_TIM9_STOP DBGMCU_CR_DBG_TIM9_STOP /*!< TIM9 counter stopped when core is halted */ | |||
| #endif /* DBGMCU_CR_DBG_TIM9_STOP */ | |||
| #if defined(DBGMCU_CR_DBG_TIM10_STOP) | |||
| #define LL_DBGMCU_APB2_GRP1_TIM10_STOP DBGMCU_CR_DBG_TIM10_STOP /*!< TIM10 counter stopped when core is halted */ | |||
| #endif /* DBGMCU_CR_DBG_TIM10_STOP */ | |||
| #if defined(DBGMCU_CR_DBG_TIM11_STOP) | |||
| #define LL_DBGMCU_APB2_GRP1_TIM11_STOP DBGMCU_CR_DBG_TIM11_STOP /*!< TIM11 counter stopped when core is halted */ | |||
| #endif /* DBGMCU_CR_DBG_TIM11_STOP */ | |||
| #if defined(DBGMCU_CR_DBG_TIM15_STOP) | |||
| #define LL_DBGMCU_APB2_GRP1_TIM15_STOP DBGMCU_CR_DBG_TIM15_STOP /*!< TIM15 counter stopped when core is halted */ | |||
| #endif /* DBGMCU_CR_DBG_TIM15_STOP */ | |||
| #if defined(DBGMCU_CR_DBG_TIM16_STOP) | |||
| #define LL_DBGMCU_APB2_GRP1_TIM16_STOP DBGMCU_CR_DBG_TIM16_STOP /*!< TIM16 counter stopped when core is halted */ | |||
| #endif /* DBGMCU_CR_DBG_TIM16_STOP */ | |||
| #if defined(DBGMCU_CR_DBG_TIM17_STOP) | |||
| #define LL_DBGMCU_APB2_GRP1_TIM17_STOP DBGMCU_CR_DBG_TIM17_STOP /*!< TIM17 counter stopped when core is halted */ | |||
| #endif /* DBGMCU_CR_DBG_TIM17_STOP */ | |||
| /** | |||
| * @} | |||
| */ | |||
| /** @defgroup SYSTEM_LL_EC_LATENCY FLASH LATENCY | |||
| * @{ | |||
| */ | |||
| #if defined(FLASH_ACR_LATENCY) | |||
| #define LL_FLASH_LATENCY_0 0x00000000U /*!< FLASH Zero Latency cycle */ | |||
| #define LL_FLASH_LATENCY_1 FLASH_ACR_LATENCY_0 /*!< FLASH One Latency cycle */ | |||
| #define LL_FLASH_LATENCY_2 FLASH_ACR_LATENCY_1 /*!< FLASH Two wait states */ | |||
| #else | |||
| #endif /* FLASH_ACR_LATENCY */ | |||
| /** | |||
| * @} | |||
| */ | |||
| /** | |||
| * @} | |||
| */ | |||
| /* Exported macro ------------------------------------------------------------*/ | |||
| /* Exported functions --------------------------------------------------------*/ | |||
| /** @defgroup SYSTEM_LL_Exported_Functions SYSTEM Exported Functions | |||
| * @{ | |||
| */ | |||
| /** @defgroup SYSTEM_LL_EF_DBGMCU DBGMCU | |||
| * @{ | |||
| */ | |||
| /** | |||
| * @brief Return the device identifier | |||
| * @note For Low Density devices, the device ID is 0x412 | |||
| * @note For Medium Density devices, the device ID is 0x410 | |||
| * @note For High Density devices, the device ID is 0x414 | |||
| * @note For XL Density devices, the device ID is 0x430 | |||
| * @note For Connectivity Line devices, the device ID is 0x418 | |||
| * @rmtoll DBGMCU_IDCODE DEV_ID LL_DBGMCU_GetDeviceID | |||
| * @retval Values between Min_Data=0x00 and Max_Data=0xFFF | |||
| */ | |||
| __STATIC_INLINE uint32_t LL_DBGMCU_GetDeviceID(void) | |||
| { | |||
| return (uint32_t)(READ_BIT(DBGMCU->IDCODE, DBGMCU_IDCODE_DEV_ID)); | |||
| } | |||
| /** | |||
| * @brief Return the device revision identifier | |||
| * @note This field indicates the revision of the device. | |||
| For example, it is read as revA -> 0x1000,for Low Density devices | |||
| For example, it is read as revA -> 0x0000, revB -> 0x2000, revZ -> 0x2001, rev1,2,3,X or Y -> 0x2003,for Medium Density devices | |||
| For example, it is read as revA or 1 -> 0x1000, revZ -> 0x1001,rev1,2,3,X or Y -> 0x1003,for Medium Density devices | |||
| For example, it is read as revA or 1 -> 0x1003,for XL Density devices | |||
| For example, it is read as revA -> 0x1000, revZ -> 0x1001 for Connectivity line devices | |||
| * @rmtoll DBGMCU_IDCODE REV_ID LL_DBGMCU_GetRevisionID | |||
| * @retval Values between Min_Data=0x00 and Max_Data=0xFFFF | |||
| */ | |||
| __STATIC_INLINE uint32_t LL_DBGMCU_GetRevisionID(void) | |||
| { | |||
| return (uint32_t)(READ_BIT(DBGMCU->IDCODE, DBGMCU_IDCODE_REV_ID) >> DBGMCU_IDCODE_REV_ID_Pos); | |||
| } | |||
| /** | |||
| * @brief Enable the Debug Module during SLEEP mode | |||
| * @rmtoll DBGMCU_CR DBG_SLEEP LL_DBGMCU_EnableDBGSleepMode | |||
| * @retval None | |||
| */ | |||
| __STATIC_INLINE void LL_DBGMCU_EnableDBGSleepMode(void) | |||
| { | |||
| SET_BIT(DBGMCU->CR, DBGMCU_CR_DBG_SLEEP); | |||
| } | |||
| /** | |||
| * @brief Disable the Debug Module during SLEEP mode | |||
| * @rmtoll DBGMCU_CR DBG_SLEEP LL_DBGMCU_DisableDBGSleepMode | |||
| * @retval None | |||
| */ | |||
| __STATIC_INLINE void LL_DBGMCU_DisableDBGSleepMode(void) | |||
| { | |||
| CLEAR_BIT(DBGMCU->CR, DBGMCU_CR_DBG_SLEEP); | |||
| } | |||
| /** | |||
| * @brief Enable the Debug Module during STOP mode | |||
| * @rmtoll DBGMCU_CR DBG_STOP LL_DBGMCU_EnableDBGStopMode | |||
| * @retval None | |||
| */ | |||
| __STATIC_INLINE void LL_DBGMCU_EnableDBGStopMode(void) | |||
| { | |||
| SET_BIT(DBGMCU->CR, DBGMCU_CR_DBG_STOP); | |||
| } | |||
| /** | |||
| * @brief Disable the Debug Module during STOP mode | |||
| * @rmtoll DBGMCU_CR DBG_STOP LL_DBGMCU_DisableDBGStopMode | |||
| * @retval None | |||
| */ | |||
| __STATIC_INLINE void LL_DBGMCU_DisableDBGStopMode(void) | |||
| { | |||
| CLEAR_BIT(DBGMCU->CR, DBGMCU_CR_DBG_STOP); | |||
| } | |||
| /** | |||
| * @brief Enable the Debug Module during STANDBY mode | |||
| * @rmtoll DBGMCU_CR DBG_STANDBY LL_DBGMCU_EnableDBGStandbyMode | |||
| * @retval None | |||
| */ | |||
| __STATIC_INLINE void LL_DBGMCU_EnableDBGStandbyMode(void) | |||
| { | |||
| SET_BIT(DBGMCU->CR, DBGMCU_CR_DBG_STANDBY); | |||
| } | |||
| /** | |||
| * @brief Disable the Debug Module during STANDBY mode | |||
| * @rmtoll DBGMCU_CR DBG_STANDBY LL_DBGMCU_DisableDBGStandbyMode | |||
| * @retval None | |||
| */ | |||
| __STATIC_INLINE void LL_DBGMCU_DisableDBGStandbyMode(void) | |||
| { | |||
| CLEAR_BIT(DBGMCU->CR, DBGMCU_CR_DBG_STANDBY); | |||
| } | |||
| /** | |||
| * @brief Set Trace pin assignment control | |||
| * @rmtoll DBGMCU_CR TRACE_IOEN LL_DBGMCU_SetTracePinAssignment\n | |||
| * DBGMCU_CR TRACE_MODE LL_DBGMCU_SetTracePinAssignment | |||
| * @param PinAssignment This parameter can be one of the following values: | |||
| * @arg @ref LL_DBGMCU_TRACE_NONE | |||
| * @arg @ref LL_DBGMCU_TRACE_ASYNCH | |||
| * @arg @ref LL_DBGMCU_TRACE_SYNCH_SIZE1 | |||
| * @arg @ref LL_DBGMCU_TRACE_SYNCH_SIZE2 | |||
| * @arg @ref LL_DBGMCU_TRACE_SYNCH_SIZE4 | |||
| * @retval None | |||
| */ | |||
| __STATIC_INLINE void LL_DBGMCU_SetTracePinAssignment(uint32_t PinAssignment) | |||
| { | |||
| MODIFY_REG(DBGMCU->CR, DBGMCU_CR_TRACE_IOEN | DBGMCU_CR_TRACE_MODE, PinAssignment); | |||
| } | |||
| /** | |||
| * @brief Get Trace pin assignment control | |||
| * @rmtoll DBGMCU_CR TRACE_IOEN LL_DBGMCU_GetTracePinAssignment\n | |||
| * DBGMCU_CR TRACE_MODE LL_DBGMCU_GetTracePinAssignment | |||
| * @retval Returned value can be one of the following values: | |||
| * @arg @ref LL_DBGMCU_TRACE_NONE | |||
| * @arg @ref LL_DBGMCU_TRACE_ASYNCH | |||
| * @arg @ref LL_DBGMCU_TRACE_SYNCH_SIZE1 | |||
| * @arg @ref LL_DBGMCU_TRACE_SYNCH_SIZE2 | |||
| * @arg @ref LL_DBGMCU_TRACE_SYNCH_SIZE4 | |||
| */ | |||
| __STATIC_INLINE uint32_t LL_DBGMCU_GetTracePinAssignment(void) | |||
| { | |||
| return (uint32_t)(READ_BIT(DBGMCU->CR, DBGMCU_CR_TRACE_IOEN | DBGMCU_CR_TRACE_MODE)); | |||
| } | |||
| /** | |||
| * @brief Freeze APB1 peripherals (group1 peripherals) | |||
| * @rmtoll DBGMCU_CR_APB1 DBG_TIM2_STOP LL_DBGMCU_APB1_GRP1_FreezePeriph\n | |||
| * DBGMCU_CR_APB1 DBG_TIM3_STOP LL_DBGMCU_APB1_GRP1_FreezePeriph\n | |||
| * DBGMCU_CR_APB1 DBG_TIM4_STOP LL_DBGMCU_APB1_GRP1_FreezePeriph\n | |||
| * DBGMCU_CR_APB1 DBG_TIM5_STOP LL_DBGMCU_APB1_GRP1_FreezePeriph\n | |||
| * DBGMCU_CR_APB1 DBG_TIM6_STOP LL_DBGMCU_APB1_GRP1_FreezePeriph\n | |||
| * DBGMCU_CR_APB1 DBG_TIM7_STOP LL_DBGMCU_APB1_GRP1_FreezePeriph\n | |||
| * DBGMCU_CR_APB1 DBG_TIM12_STOP LL_DBGMCU_APB1_GRP1_FreezePeriph\n | |||
| * DBGMCU_CR_APB1 DBG_TIM13_STOP LL_DBGMCU_APB1_GRP1_FreezePeriph\n | |||
| * DBGMCU_CR_APB1 DBG_TIM14_STOP LL_DBGMCU_APB1_GRP1_FreezePeriph\n | |||
| * DBGMCU_CR_APB1 DBG_RTC_STOP LL_DBGMCU_APB1_GRP1_FreezePeriph\n | |||
| * DBGMCU_CR_APB1 DBG_WWDG_STOP LL_DBGMCU_APB1_GRP1_FreezePeriph\n | |||
| * DBGMCU_CR_APB1 DBG_IWDG_STOP LL_DBGMCU_APB1_GRP1_FreezePeriph\n | |||
| * DBGMCU_CR_APB1 DBG_I2C1_SMBUS_TIMEOUT LL_DBGMCU_APB1_GRP1_FreezePeriph\n | |||
| * DBGMCU_CR_APB1 DBG_I2C2_SMBUS_TIMEOUT LL_DBGMCU_APB1_GRP1_FreezePeriph\n | |||
| * DBGMCU_CR_APB1 DBG_CAN1_STOP LL_DBGMCU_APB1_GRP1_FreezePeriph\n | |||
| * DBGMCU_CR_APB1 DBG_CAN2_STOP LL_DBGMCU_APB1_GRP1_FreezePeriph | |||
| * @param Periphs This parameter can be a combination of the following values: | |||
| * @arg @ref LL_DBGMCU_APB1_GRP1_TIM2_STOP | |||
| * @arg @ref LL_DBGMCU_APB1_GRP1_TIM3_STOP | |||
| * @arg @ref LL_DBGMCU_APB1_GRP1_TIM4_STOP | |||
| * @arg @ref LL_DBGMCU_APB1_GRP1_TIM5_STOP | |||
| * @arg @ref LL_DBGMCU_APB1_GRP1_TIM6_STOP | |||
| * @arg @ref LL_DBGMCU_APB1_GRP1_TIM7_STOP | |||
| * @arg @ref LL_DBGMCU_APB1_GRP1_TIM12_STOP | |||
| * @arg @ref LL_DBGMCU_APB1_GRP1_TIM13_STOP | |||
| * @arg @ref LL_DBGMCU_APB1_GRP1_TIM14_STOP | |||
| * @arg @ref LL_DBGMCU_APB1_GRP1_WWDG_STOP | |||
| * @arg @ref LL_DBGMCU_APB1_GRP1_IWDG_STOP | |||
| * @arg @ref LL_DBGMCU_APB1_GRP1_I2C1_STOP | |||
| * @arg @ref LL_DBGMCU_APB1_GRP1_I2C2_STOP (*) | |||
| * @arg @ref LL_DBGMCU_APB1_GRP1_CAN1_STOP (*) | |||
| * @arg @ref LL_DBGMCU_APB1_GRP1_CAN2_STOP (*) | |||
| * | |||
| * (*) value not defined in all devices. | |||
| * @retval None | |||
| */ | |||
| __STATIC_INLINE void LL_DBGMCU_APB1_GRP1_FreezePeriph(uint32_t Periphs) | |||
| { | |||
| SET_BIT(DBGMCU->CR, Periphs); | |||
| } | |||
| /** | |||
| * @brief Unfreeze APB1 peripherals (group1 peripherals) | |||
| * @rmtoll DBGMCU_CR_APB1 DBG_TIM2_STOP LL_DBGMCU_APB1_GRP1_UnFreezePeriph\n | |||
| * DBGMCU_CR_APB1 DBG_TIM3_STOP LL_DBGMCU_APB1_GRP1_UnFreezePeriph\n | |||
| * DBGMCU_CR_APB1 DBG_TIM4_STOP LL_DBGMCU_APB1_GRP1_UnFreezePeriph\n | |||
| * DBGMCU_CR_APB1 DBG_TIM5_STOP LL_DBGMCU_APB1_GRP1_UnFreezePeriph\n | |||
| * DBGMCU_CR_APB1 DBG_TIM6_STOP LL_DBGMCU_APB1_GRP1_UnFreezePeriph\n | |||
| * DBGMCU_CR_APB1 DBG_TIM7_STOP LL_DBGMCU_APB1_GRP1_UnFreezePeriph\n | |||
| * DBGMCU_CR_APB1 DBG_TIM12_STOP LL_DBGMCU_APB1_GRP1_UnFreezePeriph\n | |||
| * DBGMCU_CR_APB1 DBG_TIM13_STOP LL_DBGMCU_APB1_GRP1_UnFreezePeriph\n | |||
| * DBGMCU_CR_APB1 DBG_TIM14_STOP LL_DBGMCU_APB1_GRP1_UnFreezePeriph\n | |||
| * DBGMCU_CR_APB1 DBG_RTC_STOP LL_DBGMCU_APB1_GRP1_UnFreezePeriph\n | |||
| * DBGMCU_CR_APB1 DBG_WWDG_STOP LL_DBGMCU_APB1_GRP1_UnFreezePeriph\n | |||
| * DBGMCU_CR_APB1 DBG_IWDG_STOP LL_DBGMCU_APB1_GRP1_UnFreezePeriph\n | |||
| * DBGMCU_CR_APB1 DBG_I2C1_SMBUS_TIMEOUT LL_DBGMCU_APB1_GRP1_UnFreezePeriph\n | |||
| * DBGMCU_CR_APB1 DBG_I2C2_SMBUS_TIMEOUT LL_DBGMCU_APB1_GRP1_UnFreezePeriph\n | |||
| * DBGMCU_CR_APB1 DBG_CAN1_STOP LL_DBGMCU_APB1_GRP1_UnFreezePeriph\n | |||
| * DBGMCU_CR_APB1 DBG_CAN2_STOP LL_DBGMCU_APB1_GRP1_UnFreezePeriph | |||
| * @param Periphs This parameter can be a combination of the following values: | |||
| * @arg @ref LL_DBGMCU_APB1_GRP1_TIM2_STOP | |||
| * @arg @ref LL_DBGMCU_APB1_GRP1_TIM3_STOP | |||
| * @arg @ref LL_DBGMCU_APB1_GRP1_TIM4_STOP | |||
| * @arg @ref LL_DBGMCU_APB1_GRP1_TIM5_STOP | |||
| * @arg @ref LL_DBGMCU_APB1_GRP1_TIM6_STOP | |||
| * @arg @ref LL_DBGMCU_APB1_GRP1_TIM7_STOP | |||
| * @arg @ref LL_DBGMCU_APB1_GRP1_TIM12_STOP | |||
| * @arg @ref LL_DBGMCU_APB1_GRP1_TIM13_STOP | |||
| * @arg @ref LL_DBGMCU_APB1_GRP1_TIM14_STOP | |||
| * @arg @ref LL_DBGMCU_APB1_GRP1_RTC_STOP | |||
| * @arg @ref LL_DBGMCU_APB1_GRP1_WWDG_STOP | |||
| * @arg @ref LL_DBGMCU_APB1_GRP1_IWDG_STOP | |||
| * @arg @ref LL_DBGMCU_APB1_GRP1_I2C1_STOP | |||
| * @arg @ref LL_DBGMCU_APB1_GRP1_I2C2_STOP (*) | |||
| * @arg @ref LL_DBGMCU_APB1_GRP1_CAN1_STOP (*) | |||
| * @arg @ref LL_DBGMCU_APB1_GRP1_CAN2_STOP (*) | |||
| * | |||
| * (*) value not defined in all devices. | |||
| * @retval None | |||
| */ | |||
| __STATIC_INLINE void LL_DBGMCU_APB1_GRP1_UnFreezePeriph(uint32_t Periphs) | |||
| { | |||
| CLEAR_BIT(DBGMCU->CR, Periphs); | |||
| } | |||
| /** | |||
| * @brief Freeze APB2 peripherals | |||
| * @rmtoll DBGMCU_CR_APB2 DBG_TIM1_STOP LL_DBGMCU_APB2_GRP1_FreezePeriph\n | |||
| * DBGMCU_CR_APB2 DBG_TIM8_STOP LL_DBGMCU_APB2_GRP1_FreezePeriph\n | |||
| * DBGMCU_CR_APB2 DBG_TIM9_STOP LL_DBGMCU_APB2_GRP1_FreezePeriph\n | |||
| * DBGMCU_CR_APB2 DBG_TIM10_STOP LL_DBGMCU_APB2_GRP1_FreezePeriph\n | |||
| * DBGMCU_CR_APB2 DBG_TIM11_STOP LL_DBGMCU_APB2_GRP1_FreezePeriph\n | |||
| * DBGMCU_CR_APB2 DBG_TIM15_STOP LL_DBGMCU_APB2_GRP1_FreezePeriph\n | |||
| * DBGMCU_CR_APB2 DBG_TIM16_STOP LL_DBGMCU_APB2_GRP1_FreezePeriph\n | |||
| * DBGMCU_CR_APB2 DBG_TIM17_STOP LL_DBGMCU_APB2_GRP1_FreezePeriph | |||
| * @param Periphs This parameter can be a combination of the following values: | |||
| * @arg @ref LL_DBGMCU_APB2_GRP1_TIM1_STOP | |||
| * @arg @ref LL_DBGMCU_APB2_GRP1_TIM8_STOP (*) | |||
| * @arg @ref LL_DBGMCU_APB2_GRP1_TIM9_STOP (*) | |||
| * @arg @ref LL_DBGMCU_APB2_GRP1_TIM10_STOP (*) | |||
| * @arg @ref LL_DBGMCU_APB2_GRP1_TIM11_STOP (*) | |||
| * @arg @ref LL_DBGMCU_APB2_GRP1_TIM15_STOP (*) | |||
| * @arg @ref LL_DBGMCU_APB2_GRP1_TIM16_STOP (*) | |||
| * @arg @ref LL_DBGMCU_APB2_GRP1_TIM17_STOP (*) | |||
| * | |||
| * (*) value not defined in all devices. | |||
| * @retval None | |||
| */ | |||
| __STATIC_INLINE void LL_DBGMCU_APB2_GRP1_FreezePeriph(uint32_t Periphs) | |||
| { | |||
| SET_BIT(DBGMCU->CR, Periphs); | |||
| } | |||
| /** | |||
| * @brief Unfreeze APB2 peripherals | |||
| * @rmtoll DBGMCU_CR_APB2 DBG_TIM1_STOP LL_DBGMCU_APB2_GRP1_FreezePeriph\n | |||
| * DBGMCU_CR_APB2 DBG_TIM8_STOP LL_DBGMCU_APB2_GRP1_FreezePeriph\n | |||
| * DBGMCU_CR_APB2 DBG_TIM9_STOP LL_DBGMCU_APB2_GRP1_FreezePeriph\n | |||
| * DBGMCU_CR_APB2 DBG_TIM10_STOP LL_DBGMCU_APB2_GRP1_FreezePeriph\n | |||
| * DBGMCU_CR_APB2 DBG_TIM11_STOP LL_DBGMCU_APB2_GRP1_FreezePeriph\n | |||
| * DBGMCU_CR_APB2 DBG_TIM15_STOP LL_DBGMCU_APB2_GRP1_FreezePeriph\n | |||
| * DBGMCU_CR_APB2 DBG_TIM16_STOP LL_DBGMCU_APB2_GRP1_FreezePeriph\n | |||
| * DBGMCU_CR_APB2 DBG_TIM17_STOP LL_DBGMCU_APB2_GRP1_FreezePeriph | |||
| * @param Periphs This parameter can be a combination of the following values: | |||
| * @arg @ref LL_DBGMCU_APB2_GRP1_TIM1_STOP | |||
| * @arg @ref LL_DBGMCU_APB2_GRP1_TIM8_STOP (*) | |||
| * @arg @ref LL_DBGMCU_APB2_GRP1_TIM9_STOP (*) | |||
| * @arg @ref LL_DBGMCU_APB2_GRP1_TIM10_STOP (*) | |||
| * @arg @ref LL_DBGMCU_APB2_GRP1_TIM11_STOP (*) | |||
| * @arg @ref LL_DBGMCU_APB2_GRP1_TIM15_STOP (*) | |||
| * @arg @ref LL_DBGMCU_APB2_GRP1_TIM16_STOP (*) | |||
| * @arg @ref LL_DBGMCU_APB2_GRP1_TIM17_STOP (*) | |||
| * | |||
| * (*) value not defined in all devices. | |||
| * @retval None | |||
| */ | |||
| __STATIC_INLINE void LL_DBGMCU_APB2_GRP1_UnFreezePeriph(uint32_t Periphs) | |||
| { | |||
| CLEAR_BIT(DBGMCU->CR, Periphs); | |||
| } | |||
| /** | |||
| * @} | |||
| */ | |||
| #if defined(FLASH_ACR_LATENCY) | |||
| /** @defgroup SYSTEM_LL_EF_FLASH FLASH | |||
| * @{ | |||
| */ | |||
| /** | |||
| * @brief Set FLASH Latency | |||
| * @rmtoll FLASH_ACR LATENCY LL_FLASH_SetLatency | |||
| * @param Latency This parameter can be one of the following values: | |||
| * @arg @ref LL_FLASH_LATENCY_0 | |||
| * @arg @ref LL_FLASH_LATENCY_1 | |||
| * @arg @ref LL_FLASH_LATENCY_2 | |||
| * @retval None | |||
| */ | |||
| __STATIC_INLINE void LL_FLASH_SetLatency(uint32_t Latency) | |||
| { | |||
| MODIFY_REG(FLASH->ACR, FLASH_ACR_LATENCY, Latency); | |||
| } | |||
| /** | |||
| * @brief Get FLASH Latency | |||
| * @rmtoll FLASH_ACR LATENCY LL_FLASH_GetLatency | |||
| * @retval Returned value can be one of the following values: | |||
| * @arg @ref LL_FLASH_LATENCY_0 | |||
| * @arg @ref LL_FLASH_LATENCY_1 | |||
| * @arg @ref LL_FLASH_LATENCY_2 | |||
| */ | |||
| __STATIC_INLINE uint32_t LL_FLASH_GetLatency(void) | |||
| { | |||
| return (uint32_t)(READ_BIT(FLASH->ACR, FLASH_ACR_LATENCY)); | |||
| } | |||
| /** | |||
| * @brief Enable Prefetch | |||
| * @rmtoll FLASH_ACR PRFTBE LL_FLASH_EnablePrefetch | |||
| * @retval None | |||
| */ | |||
| __STATIC_INLINE void LL_FLASH_EnablePrefetch(void) | |||
| { | |||
| SET_BIT(FLASH->ACR, FLASH_ACR_PRFTBE); | |||
| } | |||
| /** | |||
| * @brief Disable Prefetch | |||
| * @rmtoll FLASH_ACR PRFTBE LL_FLASH_DisablePrefetch | |||
| * @retval None | |||
| */ | |||
| __STATIC_INLINE void LL_FLASH_DisablePrefetch(void) | |||
| { | |||
| CLEAR_BIT(FLASH->ACR, FLASH_ACR_PRFTBE); | |||
| } | |||
| /** | |||
| * @brief Check if Prefetch buffer is enabled | |||
| * @rmtoll FLASH_ACR PRFTBS LL_FLASH_IsPrefetchEnabled | |||
| * @retval State of bit (1 or 0). | |||
| */ | |||
| __STATIC_INLINE uint32_t LL_FLASH_IsPrefetchEnabled(void) | |||
| { | |||
| return (READ_BIT(FLASH->ACR, FLASH_ACR_PRFTBS) == (FLASH_ACR_PRFTBS)); | |||
| } | |||
| #endif /* FLASH_ACR_LATENCY */ | |||
| /** | |||
| * @brief Enable Flash Half Cycle Access | |||
| * @rmtoll FLASH_ACR HLFCYA LL_FLASH_EnableHalfCycleAccess | |||
| * @retval None | |||
| */ | |||
| __STATIC_INLINE void LL_FLASH_EnableHalfCycleAccess(void) | |||
| { | |||
| SET_BIT(FLASH->ACR, FLASH_ACR_HLFCYA); | |||
| } | |||
| /** | |||
| * @brief Disable Flash Half Cycle Access | |||
| * @rmtoll FLASH_ACR HLFCYA LL_FLASH_DisableHalfCycleAccess | |||
| * @retval None | |||
| */ | |||
| __STATIC_INLINE void LL_FLASH_DisableHalfCycleAccess(void) | |||
| { | |||
| CLEAR_BIT(FLASH->ACR, FLASH_ACR_HLFCYA); | |||
| } | |||
| /** | |||
| * @brief Check if Flash Half Cycle Access is enabled or not | |||
| * @rmtoll FLASH_ACR HLFCYA LL_FLASH_IsHalfCycleAccessEnabled | |||
| * @retval State of bit (1 or 0). | |||
| */ | |||
| __STATIC_INLINE uint32_t LL_FLASH_IsHalfCycleAccessEnabled(void) | |||
| { | |||
| return (READ_BIT(FLASH->ACR, FLASH_ACR_HLFCYA) == (FLASH_ACR_HLFCYA)); | |||
| } | |||
| /** | |||
| * @} | |||
| */ | |||
| /** | |||
| * @} | |||
| */ | |||
| /** | |||
| * @} | |||
| */ | |||
| #endif /* defined (FLASH) || defined (DBGMCU) */ | |||
| /** | |||
| * @} | |||
| */ | |||
| #ifdef __cplusplus | |||
| } | |||
| #endif | |||
| #endif /* __STM32F1xx_LL_SYSTEM_H */ | |||
| @ -0,0 +1,270 @@ | |||
| /** | |||
| ****************************************************************************** | |||
| * @file stm32f1xx_ll_utils.h | |||
| * @author MCD Application Team | |||
| * @brief Header file of UTILS LL module. | |||
| ****************************************************************************** | |||
| * @attention | |||
| * | |||
| * Copyright (c) 2016 STMicroelectronics. | |||
| * All rights reserved. | |||
| * | |||
| * This software is licensed under terms that can be found in the LICENSE file | |||
| * in the root directory of this software component. | |||
| * If no LICENSE file comes with this software, it is provided AS-IS. | |||
| * | |||
| ****************************************************************************** | |||
| @verbatim | |||
| ============================================================================== | |||
| ##### How to use this driver ##### | |||
| ============================================================================== | |||
| [..] | |||
| The LL UTILS driver contains a set of generic APIs that can be | |||
| used by user: | |||
| (+) Device electronic signature | |||
| (+) Timing functions | |||
| (+) PLL configuration functions | |||
| @endverbatim | |||
| ****************************************************************************** | |||
| */ | |||
| /* Define to prevent recursive inclusion -------------------------------------*/ | |||
| #ifndef __STM32F1xx_LL_UTILS_H | |||
| #define __STM32F1xx_LL_UTILS_H | |||
| #ifdef __cplusplus | |||
| extern "C" { | |||
| #endif | |||
| /* Includes ------------------------------------------------------------------*/ | |||
| #include "stm32f1xx.h" | |||
| /** @addtogroup STM32F1xx_LL_Driver | |||
| * @{ | |||
| */ | |||
| /** @defgroup UTILS_LL UTILS | |||
| * @{ | |||
| */ | |||
| /* Private types -------------------------------------------------------------*/ | |||
| /* Private variables ---------------------------------------------------------*/ | |||
| /* Private constants ---------------------------------------------------------*/ | |||
| /** @defgroup UTILS_LL_Private_Constants UTILS Private Constants | |||
| * @{ | |||
| */ | |||
| /* Max delay can be used in LL_mDelay */ | |||
| #define LL_MAX_DELAY 0xFFFFFFFFU | |||
| /** | |||
| * @brief Unique device ID register base address | |||
| */ | |||
| #define UID_BASE_ADDRESS UID_BASE | |||
| /** | |||
| * @brief Flash size data register base address | |||
| */ | |||
| #define FLASHSIZE_BASE_ADDRESS FLASHSIZE_BASE | |||
| /** | |||
| * @} | |||
| */ | |||
| /* Private macros ------------------------------------------------------------*/ | |||
| /** @defgroup UTILS_LL_Private_Macros UTILS Private Macros | |||
| * @{ | |||
| */ | |||
| /** | |||
| * @} | |||
| */ | |||
| /* Exported types ------------------------------------------------------------*/ | |||
| /** @defgroup UTILS_LL_ES_INIT UTILS Exported structures | |||
| * @{ | |||
| */ | |||
| /** | |||
| * @brief UTILS PLL structure definition | |||
| */ | |||
| typedef struct | |||
| { | |||
| uint32_t PLLMul; /*!< Multiplication factor for PLL VCO input clock. | |||
| This parameter can be a value of @ref RCC_LL_EC_PLL_MUL | |||
| This feature can be modified afterwards using unitary function | |||
| @ref LL_RCC_PLL_ConfigDomain_SYS(). */ | |||
| uint32_t Prediv; /*!< Division factor for HSE used as PLL clock source. | |||
| This parameter can be a value of @ref RCC_LL_EC_PREDIV_DIV | |||
| This feature can be modified afterwards using unitary function | |||
| @ref LL_RCC_PLL_ConfigDomain_SYS(). */ | |||
| } LL_UTILS_PLLInitTypeDef; | |||
| /** | |||
| * @brief UTILS System, AHB and APB buses clock configuration structure definition | |||
| */ | |||
| typedef struct | |||
| { | |||
| uint32_t AHBCLKDivider; /*!< The AHB clock (HCLK) divider. This clock is derived from the system clock (SYSCLK). | |||
| This parameter can be a value of @ref RCC_LL_EC_SYSCLK_DIV | |||
| This feature can be modified afterwards using unitary function | |||
| @ref LL_RCC_SetAHBPrescaler(). */ | |||
| uint32_t APB1CLKDivider; /*!< The APB1 clock (PCLK1) divider. This clock is derived from the AHB clock (HCLK). | |||
| This parameter can be a value of @ref RCC_LL_EC_APB1_DIV | |||
| This feature can be modified afterwards using unitary function | |||
| @ref LL_RCC_SetAPB1Prescaler(). */ | |||
| uint32_t APB2CLKDivider; /*!< The APB2 clock (PCLK2) divider. This clock is derived from the AHB clock (HCLK). | |||
| This parameter can be a value of @ref RCC_LL_EC_APB2_DIV | |||
| This feature can be modified afterwards using unitary function | |||
| @ref LL_RCC_SetAPB2Prescaler(). */ | |||
| } LL_UTILS_ClkInitTypeDef; | |||
| /** | |||
| * @} | |||
| */ | |||
| /* Exported constants --------------------------------------------------------*/ | |||
| /** @defgroup UTILS_LL_Exported_Constants UTILS Exported Constants | |||
| * @{ | |||
| */ | |||
| /** @defgroup UTILS_EC_HSE_BYPASS HSE Bypass activation | |||
| * @{ | |||
| */ | |||
| #define LL_UTILS_HSEBYPASS_OFF 0x00000000U /*!< HSE Bypass is not enabled */ | |||
| #define LL_UTILS_HSEBYPASS_ON 0x00000001U /*!< HSE Bypass is enabled */ | |||
| /** | |||
| * @} | |||
| */ | |||
| /** | |||
| * @} | |||
| */ | |||
| /* Exported macro ------------------------------------------------------------*/ | |||
| /* Exported functions --------------------------------------------------------*/ | |||
| /** @defgroup UTILS_LL_Exported_Functions UTILS Exported Functions | |||
| * @{ | |||
| */ | |||
| /** @defgroup UTILS_EF_DEVICE_ELECTRONIC_SIGNATURE DEVICE ELECTRONIC SIGNATURE | |||
| * @{ | |||
| */ | |||
| /** | |||
| * @brief Get Word0 of the unique device identifier (UID based on 96 bits) | |||
| * @retval UID[31:0] | |||
| */ | |||
| __STATIC_INLINE uint32_t LL_GetUID_Word0(void) | |||
| { | |||
| return (uint32_t)(READ_REG(*((uint32_t *)UID_BASE_ADDRESS))); | |||
| } | |||
| /** | |||
| * @brief Get Word1 of the unique device identifier (UID based on 96 bits) | |||
| * @retval UID[63:32] | |||
| */ | |||
| __STATIC_INLINE uint32_t LL_GetUID_Word1(void) | |||
| { | |||
| return (uint32_t)(READ_REG(*((uint32_t *)(UID_BASE_ADDRESS + 4U)))); | |||
| } | |||
| /** | |||
| * @brief Get Word2 of the unique device identifier (UID based on 96 bits) | |||
| * @retval UID[95:64] | |||
| */ | |||
| __STATIC_INLINE uint32_t LL_GetUID_Word2(void) | |||
| { | |||
| return (uint32_t)(READ_REG(*((uint32_t *)(UID_BASE_ADDRESS + 8U)))); | |||
| } | |||
| /** | |||
| * @brief Get Flash memory size | |||
| * @note This bitfield indicates the size of the device Flash memory expressed in | |||
| * Kbytes. As an example, 0x040 corresponds to 64 Kbytes. | |||
| * @retval FLASH_SIZE[15:0]: Flash memory size | |||
| */ | |||
| __STATIC_INLINE uint32_t LL_GetFlashSize(void) | |||
| { | |||
| return (uint16_t)(READ_REG(*((uint32_t *)FLASHSIZE_BASE_ADDRESS))); | |||
| } | |||
| /** | |||
| * @} | |||
| */ | |||
| /** @defgroup UTILS_LL_EF_DELAY DELAY | |||
| * @{ | |||
| */ | |||
| /** | |||
| * @brief This function configures the Cortex-M SysTick source of the time base. | |||
| * @param HCLKFrequency HCLK frequency in Hz (can be calculated thanks to RCC helper macro) | |||
| * @note When a RTOS is used, it is recommended to avoid changing the SysTick | |||
| * configuration by calling this function, for a delay use rather osDelay RTOS service. | |||
| * @param Ticks Number of ticks | |||
| * @retval None | |||
| */ | |||
| __STATIC_INLINE void LL_InitTick(uint32_t HCLKFrequency, uint32_t Ticks) | |||
| { | |||
| /* Configure the SysTick to have interrupt in 1ms time base */ | |||
| SysTick->LOAD = (uint32_t)((HCLKFrequency / Ticks) - 1UL); /* set reload register */ | |||
| SysTick->VAL = 0UL; /* Load the SysTick Counter Value */ | |||
| SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | | |||
| SysTick_CTRL_ENABLE_Msk; /* Enable the Systick Timer */ | |||
| } | |||
| void LL_Init1msTick(uint32_t HCLKFrequency); | |||
| void LL_mDelay(uint32_t Delay); | |||
| /** | |||
| * @} | |||
| */ | |||
| /** @defgroup UTILS_EF_SYSTEM SYSTEM | |||
| * @{ | |||
| */ | |||
| void LL_SetSystemCoreClock(uint32_t HCLKFrequency); | |||
| #if defined(FLASH_ACR_LATENCY) | |||
| ErrorStatus LL_SetFlashLatency(uint32_t Frequency); | |||
| #endif /* FLASH_ACR_LATENCY */ | |||
| ErrorStatus LL_PLL_ConfigSystemClock_HSI(LL_UTILS_PLLInitTypeDef *UTILS_PLLInitStruct, | |||
| LL_UTILS_ClkInitTypeDef *UTILS_ClkInitStruct); | |||
| ErrorStatus LL_PLL_ConfigSystemClock_HSE(uint32_t HSEFrequency, uint32_t HSEBypass, | |||
| LL_UTILS_PLLInitTypeDef *UTILS_PLLInitStruct, LL_UTILS_ClkInitTypeDef *UTILS_ClkInitStruct); | |||
| #if defined(RCC_PLL2_SUPPORT) | |||
| ErrorStatus LL_PLL_ConfigSystemClock_PLL2(uint32_t HSEFrequency, uint32_t HSEBypass, LL_UTILS_PLLInitTypeDef *UTILS_PLLInitStruct, | |||
| LL_UTILS_PLLInitTypeDef *UTILS_PLL2InitStruct, LL_UTILS_ClkInitTypeDef *UTILS_ClkInitStruct); | |||
| #endif /* RCC_PLL2_SUPPORT */ | |||
| /** | |||
| * @} | |||
| */ | |||
| /** | |||
| * @} | |||
| */ | |||
| /** | |||
| * @} | |||
| */ | |||
| /** | |||
| * @} | |||
| */ | |||
| #ifdef __cplusplus | |||
| } | |||
| #endif | |||
| #endif /* __STM32F1xx_LL_UTILS_H */ | |||
| @ -0,0 +1,6 @@ | |||
| This software component is provided to you as part of a software package and | |||
| applicable license terms are in the Package_license file. If you received this | |||
| software component outside of a package or without applicable license terms, | |||
| the terms of the BSD-3-Clause license shall apply. | |||
| You may obtain a copy of the BSD-3-Clause at: | |||
| https://opensource.org/licenses/BSD-3-Clause | |||
| @ -1,7 +0,0 @@ | |||
| <?xml version="1.0" encoding="UTF-8"?> | |||
| <workspace> | |||
| <project> | |||
| <path>$WS_DIR$\F103C8T6_DIGI_USB.ewp</path> | |||
| </project> | |||
| <batchBuild /> | |||
| </workspace> | |||
| @ -1,393 +0,0 @@ | |||
| ;******************** (C) COPYRIGHT 2017 STMicroelectronics ******************** | |||
| ;* File Name : startup_stm32f103xb.s | |||
| ;* Author : MCD Application Team | |||
| ;* Description : STM32F103xB Performance Line Devices vector table for | |||
| ;* EWARM toolchain. | |||
| ;* This module performs: | |||
| ;* - Set the initial SP | |||
| ;* - Configure the clock system | |||
| ;* - Set the initial PC == __iar_program_start, | |||
| ;* - Set the vector table entries with the exceptions ISR | |||
| ;* address. | |||
| ;* After Reset the Cortex-M3 processor is in Thread mode, | |||
| ;* priority is Privileged, and the Stack is set to Main. | |||
| ;******************************************************************************* | |||
| ;* @attention | |||
| ;* | |||
| ;* <h2><center>© Copyright (c) 2017 STMicroelectronics. | |||
| ;* All rights reserved.</center></h2> | |||
| ;* | |||
| ;* This software component is licensed by ST under BSD 3-Clause license, | |||
| ;* the "License"; You may not use this file except in compliance with the | |||
| ;* License. You may obtain a copy of the License at: | |||
| ;* opensource.org/licenses/BSD-3-Clause | |||
| ;* | |||
| ;******************************************************************************* | |||
| ; | |||
| ; | |||
| ; The modules in this file are included in the libraries, and may be replaced | |||
| ; by any user-defined modules that define the PUBLIC symbol _program_start or | |||
| ; a user defined start symbol. | |||
| ; To override the cstartup defined in the library, simply add your modified | |||
| ; version to the workbench project. | |||
| ; | |||
| ; The vector table is normally located at address 0. | |||
| ; When debugging in RAM, it can be located in RAM, aligned to at least 2^6. | |||
| ; The name "__vector_table" has special meaning for C-SPY: | |||
| ; it is where the SP start value is found, and the NVIC vector | |||
| ; table register (VTOR) is initialized to this address if != 0. | |||
| ; | |||
| ; Cortex-M version | |||
| ; | |||
| MODULE ?cstartup | |||
| ;; Forward declaration of sections. | |||
| SECTION CSTACK:DATA:NOROOT(3) | |||
| SECTION .intvec:CODE:NOROOT(2) | |||
| EXTERN __iar_program_start | |||
| EXTERN SystemInit | |||
| PUBLIC __vector_table | |||
| DATA | |||
| __vector_table | |||
| DCD sfe(CSTACK) | |||
| DCD Reset_Handler ; Reset Handler | |||
| DCD NMI_Handler ; NMI Handler | |||
| DCD HardFault_Handler ; Hard Fault Handler | |||
| DCD MemManage_Handler ; MPU Fault Handler | |||
| DCD BusFault_Handler ; Bus Fault Handler | |||
| DCD UsageFault_Handler ; Usage Fault Handler | |||
| DCD 0 ; Reserved | |||
| DCD 0 ; Reserved | |||
| DCD 0 ; Reserved | |||
| DCD 0 ; Reserved | |||
| DCD SVC_Handler ; SVCall Handler | |||
| DCD DebugMon_Handler ; Debug Monitor Handler | |||
| DCD 0 ; Reserved | |||
| DCD PendSV_Handler ; PendSV Handler | |||
| DCD SysTick_Handler ; SysTick Handler | |||
| ; External Interrupts | |||
| DCD WWDG_IRQHandler ; Window Watchdog | |||
| DCD PVD_IRQHandler ; PVD through EXTI Line detect | |||
| DCD TAMPER_IRQHandler ; Tamper | |||
| DCD RTC_IRQHandler ; RTC | |||
| DCD FLASH_IRQHandler ; Flash | |||
| DCD RCC_IRQHandler ; RCC | |||
| DCD EXTI0_IRQHandler ; EXTI Line 0 | |||
| DCD EXTI1_IRQHandler ; EXTI Line 1 | |||
| DCD EXTI2_IRQHandler ; EXTI Line 2 | |||
| DCD EXTI3_IRQHandler ; EXTI Line 3 | |||
| DCD EXTI4_IRQHandler ; EXTI Line 4 | |||
| DCD DMA1_Channel1_IRQHandler ; DMA1 Channel 1 | |||
| DCD DMA1_Channel2_IRQHandler ; DMA1 Channel 2 | |||
| DCD DMA1_Channel3_IRQHandler ; DMA1 Channel 3 | |||
| DCD DMA1_Channel4_IRQHandler ; DMA1 Channel 4 | |||
| DCD DMA1_Channel5_IRQHandler ; DMA1 Channel 5 | |||
| DCD DMA1_Channel6_IRQHandler ; DMA1 Channel 6 | |||
| DCD DMA1_Channel7_IRQHandler ; DMA1 Channel 7 | |||
| DCD ADC1_2_IRQHandler ; ADC1 & ADC2 | |||
| DCD USB_HP_CAN1_TX_IRQHandler ; USB High Priority or CAN1 TX | |||
| DCD USB_LP_CAN1_RX0_IRQHandler ; USB Low Priority or CAN1 RX0 | |||
| DCD CAN1_RX1_IRQHandler ; CAN1 RX1 | |||
| DCD CAN1_SCE_IRQHandler ; CAN1 SCE | |||
| DCD EXTI9_5_IRQHandler ; EXTI Line 9..5 | |||
| DCD TIM1_BRK_IRQHandler ; TIM1 Break | |||
| DCD TIM1_UP_IRQHandler ; TIM1 Update | |||
| DCD TIM1_TRG_COM_IRQHandler ; TIM1 Trigger and Commutation | |||
| DCD TIM1_CC_IRQHandler ; TIM1 Capture Compare | |||
| DCD TIM2_IRQHandler ; TIM2 | |||
| DCD TIM3_IRQHandler ; TIM3 | |||
| DCD TIM4_IRQHandler ; TIM4 | |||
| DCD I2C1_EV_IRQHandler ; I2C1 Event | |||
| DCD I2C1_ER_IRQHandler ; I2C1 Error | |||
| DCD I2C2_EV_IRQHandler ; I2C2 Event | |||
| DCD I2C2_ER_IRQHandler ; I2C2 Error | |||
| DCD SPI1_IRQHandler ; SPI1 | |||
| DCD SPI2_IRQHandler ; SPI2 | |||
| DCD USART1_IRQHandler ; USART1 | |||
| DCD USART2_IRQHandler ; USART2 | |||
| DCD USART3_IRQHandler ; USART3 | |||
| DCD EXTI15_10_IRQHandler ; EXTI Line 15..10 | |||
| DCD RTC_Alarm_IRQHandler ; RTC Alarm through EXTI Line | |||
| DCD USBWakeUp_IRQHandler ; USB Wakeup from suspend | |||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |||
| ;; | |||
| ;; Default interrupt handlers. | |||
| ;; | |||
| THUMB | |||
| PUBWEAK Reset_Handler | |||
| SECTION .text:CODE:REORDER:NOROOT(2) | |||
| Reset_Handler | |||
| LDR R0, =SystemInit | |||
| BLX R0 | |||
| LDR R0, =__iar_program_start | |||
| BX R0 | |||
| PUBWEAK NMI_Handler | |||
| SECTION .text:CODE:REORDER:NOROOT(1) | |||
| NMI_Handler | |||
| B NMI_Handler | |||
| PUBWEAK HardFault_Handler | |||
| SECTION .text:CODE:REORDER:NOROOT(1) | |||
| HardFault_Handler | |||
| B HardFault_Handler | |||
| PUBWEAK MemManage_Handler | |||
| SECTION .text:CODE:REORDER:NOROOT(1) | |||
| MemManage_Handler | |||
| B MemManage_Handler | |||
| PUBWEAK BusFault_Handler | |||
| SECTION .text:CODE:REORDER:NOROOT(1) | |||
| BusFault_Handler | |||
| B BusFault_Handler | |||
| PUBWEAK UsageFault_Handler | |||
| SECTION .text:CODE:REORDER:NOROOT(1) | |||
| UsageFault_Handler | |||
| B UsageFault_Handler | |||
| PUBWEAK SVC_Handler | |||
| SECTION .text:CODE:REORDER:NOROOT(1) | |||
| SVC_Handler | |||
| B SVC_Handler | |||
| PUBWEAK DebugMon_Handler | |||
| SECTION .text:CODE:REORDER:NOROOT(1) | |||
| DebugMon_Handler | |||
| B DebugMon_Handler | |||
| PUBWEAK PendSV_Handler | |||
| SECTION .text:CODE:REORDER:NOROOT(1) | |||
| PendSV_Handler | |||
| B PendSV_Handler | |||
| PUBWEAK SysTick_Handler | |||
| SECTION .text:CODE:REORDER:NOROOT(1) | |||
| SysTick_Handler | |||
| B SysTick_Handler | |||
| PUBWEAK WWDG_IRQHandler | |||
| SECTION .text:CODE:REORDER:NOROOT(1) | |||
| WWDG_IRQHandler | |||
| B WWDG_IRQHandler | |||
| PUBWEAK PVD_IRQHandler | |||
| SECTION .text:CODE:REORDER:NOROOT(1) | |||
| PVD_IRQHandler | |||
| B PVD_IRQHandler | |||
| PUBWEAK TAMPER_IRQHandler | |||
| SECTION .text:CODE:REORDER:NOROOT(1) | |||
| TAMPER_IRQHandler | |||
| B TAMPER_IRQHandler | |||
| PUBWEAK RTC_IRQHandler | |||
| SECTION .text:CODE:REORDER:NOROOT(1) | |||
| RTC_IRQHandler | |||
| B RTC_IRQHandler | |||
| PUBWEAK FLASH_IRQHandler | |||
| SECTION .text:CODE:REORDER:NOROOT(1) | |||
| FLASH_IRQHandler | |||
| B FLASH_IRQHandler | |||
| PUBWEAK RCC_IRQHandler | |||
| SECTION .text:CODE:REORDER:NOROOT(1) | |||
| RCC_IRQHandler | |||
| B RCC_IRQHandler | |||
| PUBWEAK EXTI0_IRQHandler | |||
| SECTION .text:CODE:REORDER:NOROOT(1) | |||
| EXTI0_IRQHandler | |||
| B EXTI0_IRQHandler | |||
| PUBWEAK EXTI1_IRQHandler | |||
| SECTION .text:CODE:REORDER:NOROOT(1) | |||
| EXTI1_IRQHandler | |||
| B EXTI1_IRQHandler | |||
| PUBWEAK EXTI2_IRQHandler | |||
| SECTION .text:CODE:REORDER:NOROOT(1) | |||
| EXTI2_IRQHandler | |||
| B EXTI2_IRQHandler | |||
| PUBWEAK EXTI3_IRQHandler | |||
| SECTION .text:CODE:REORDER:NOROOT(1) | |||
| EXTI3_IRQHandler | |||
| B EXTI3_IRQHandler | |||
| PUBWEAK EXTI4_IRQHandler | |||
| SECTION .text:CODE:REORDER:NOROOT(1) | |||
| EXTI4_IRQHandler | |||
| B EXTI4_IRQHandler | |||
| PUBWEAK DMA1_Channel1_IRQHandler | |||
| SECTION .text:CODE:REORDER:NOROOT(1) | |||
| DMA1_Channel1_IRQHandler | |||
| B DMA1_Channel1_IRQHandler | |||
| PUBWEAK DMA1_Channel2_IRQHandler | |||
| SECTION .text:CODE:REORDER:NOROOT(1) | |||
| DMA1_Channel2_IRQHandler | |||
| B DMA1_Channel2_IRQHandler | |||
| PUBWEAK DMA1_Channel3_IRQHandler | |||
| SECTION .text:CODE:REORDER:NOROOT(1) | |||
| DMA1_Channel3_IRQHandler | |||
| B DMA1_Channel3_IRQHandler | |||
| PUBWEAK DMA1_Channel4_IRQHandler | |||
| SECTION .text:CODE:REORDER:NOROOT(1) | |||
| DMA1_Channel4_IRQHandler | |||
| B DMA1_Channel4_IRQHandler | |||
| PUBWEAK DMA1_Channel5_IRQHandler | |||
| SECTION .text:CODE:REORDER:NOROOT(1) | |||
| DMA1_Channel5_IRQHandler | |||
| B DMA1_Channel5_IRQHandler | |||
| PUBWEAK DMA1_Channel6_IRQHandler | |||
| SECTION .text:CODE:REORDER:NOROOT(1) | |||
| DMA1_Channel6_IRQHandler | |||
| B DMA1_Channel6_IRQHandler | |||
| PUBWEAK DMA1_Channel7_IRQHandler | |||
| SECTION .text:CODE:REORDER:NOROOT(1) | |||
| DMA1_Channel7_IRQHandler | |||
| B DMA1_Channel7_IRQHandler | |||
| PUBWEAK ADC1_2_IRQHandler | |||
| SECTION .text:CODE:REORDER:NOROOT(1) | |||
| ADC1_2_IRQHandler | |||
| B ADC1_2_IRQHandler | |||
| PUBWEAK USB_HP_CAN1_TX_IRQHandler | |||
| SECTION .text:CODE:REORDER:NOROOT(1) | |||
| USB_HP_CAN1_TX_IRQHandler | |||
| B USB_HP_CAN1_TX_IRQHandler | |||
| PUBWEAK USB_LP_CAN1_RX0_IRQHandler | |||
| SECTION .text:CODE:REORDER:NOROOT(1) | |||
| USB_LP_CAN1_RX0_IRQHandler | |||
| B USB_LP_CAN1_RX0_IRQHandler | |||
| PUBWEAK CAN1_RX1_IRQHandler | |||
| SECTION .text:CODE:REORDER:NOROOT(1) | |||
| CAN1_RX1_IRQHandler | |||
| B CAN1_RX1_IRQHandler | |||
| PUBWEAK CAN1_SCE_IRQHandler | |||
| SECTION .text:CODE:REORDER:NOROOT(1) | |||
| CAN1_SCE_IRQHandler | |||
| B CAN1_SCE_IRQHandler | |||
| PUBWEAK EXTI9_5_IRQHandler | |||
| SECTION .text:CODE:REORDER:NOROOT(1) | |||
| EXTI9_5_IRQHandler | |||
| B EXTI9_5_IRQHandler | |||
| PUBWEAK TIM1_BRK_IRQHandler | |||
| SECTION .text:CODE:REORDER:NOROOT(1) | |||
| TIM1_BRK_IRQHandler | |||
| B TIM1_BRK_IRQHandler | |||
| PUBWEAK TIM1_UP_IRQHandler | |||
| SECTION .text:CODE:REORDER:NOROOT(1) | |||
| TIM1_UP_IRQHandler | |||
| B TIM1_UP_IRQHandler | |||
| PUBWEAK TIM1_TRG_COM_IRQHandler | |||
| SECTION .text:CODE:REORDER:NOROOT(1) | |||
| TIM1_TRG_COM_IRQHandler | |||
| B TIM1_TRG_COM_IRQHandler | |||
| PUBWEAK TIM1_CC_IRQHandler | |||
| SECTION .text:CODE:REORDER:NOROOT(1) | |||
| TIM1_CC_IRQHandler | |||
| B TIM1_CC_IRQHandler | |||
| PUBWEAK TIM2_IRQHandler | |||
| SECTION .text:CODE:REORDER:NOROOT(1) | |||
| TIM2_IRQHandler | |||
| B TIM2_IRQHandler | |||
| PUBWEAK TIM3_IRQHandler | |||
| SECTION .text:CODE:REORDER:NOROOT(1) | |||
| TIM3_IRQHandler | |||
| B TIM3_IRQHandler | |||
| PUBWEAK TIM4_IRQHandler | |||
| SECTION .text:CODE:REORDER:NOROOT(1) | |||
| TIM4_IRQHandler | |||
| B TIM4_IRQHandler | |||
| PUBWEAK I2C1_EV_IRQHandler | |||
| SECTION .text:CODE:REORDER:NOROOT(1) | |||
| I2C1_EV_IRQHandler | |||
| B I2C1_EV_IRQHandler | |||
| PUBWEAK I2C1_ER_IRQHandler | |||
| SECTION .text:CODE:REORDER:NOROOT(1) | |||
| I2C1_ER_IRQHandler | |||
| B I2C1_ER_IRQHandler | |||
| PUBWEAK I2C2_EV_IRQHandler | |||
| SECTION .text:CODE:REORDER:NOROOT(1) | |||
| I2C2_EV_IRQHandler | |||
| B I2C2_EV_IRQHandler | |||
| PUBWEAK I2C2_ER_IRQHandler | |||
| SECTION .text:CODE:REORDER:NOROOT(1) | |||
| I2C2_ER_IRQHandler | |||
| B I2C2_ER_IRQHandler | |||
| PUBWEAK SPI1_IRQHandler | |||
| SECTION .text:CODE:REORDER:NOROOT(1) | |||
| SPI1_IRQHandler | |||
| B SPI1_IRQHandler | |||
| PUBWEAK SPI2_IRQHandler | |||
| SECTION .text:CODE:REORDER:NOROOT(1) | |||
| SPI2_IRQHandler | |||
| B SPI2_IRQHandler | |||
| PUBWEAK USART1_IRQHandler | |||
| SECTION .text:CODE:REORDER:NOROOT(1) | |||
| USART1_IRQHandler | |||
| B USART1_IRQHandler | |||
| PUBWEAK USART2_IRQHandler | |||
| SECTION .text:CODE:REORDER:NOROOT(1) | |||
| USART2_IRQHandler | |||
| B USART2_IRQHandler | |||
| PUBWEAK USART3_IRQHandler | |||
| SECTION .text:CODE:REORDER:NOROOT(1) | |||
| USART3_IRQHandler | |||
| B USART3_IRQHandler | |||
| PUBWEAK EXTI15_10_IRQHandler | |||
| SECTION .text:CODE:REORDER:NOROOT(1) | |||
| EXTI15_10_IRQHandler | |||
| B EXTI15_10_IRQHandler | |||
| PUBWEAK RTC_Alarm_IRQHandler | |||
| SECTION .text:CODE:REORDER:NOROOT(1) | |||
| RTC_Alarm_IRQHandler | |||
| B RTC_Alarm_IRQHandler | |||
| PUBWEAK USBWakeUp_IRQHandler | |||
| SECTION .text:CODE:REORDER:NOROOT(1) | |||
| USBWakeUp_IRQHandler | |||
| B USBWakeUp_IRQHandler | |||
| END | |||
| /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ | |||
| @ -1,31 +0,0 @@ | |||
| /*###ICF### Section handled by ICF editor, don't touch! ****/ | |||
| /*-Editor annotation file-*/ | |||
| /* IcfEditorFile="$TOOLKIT_DIR$\config\ide\IcfEditor\cortex_v1_0.xml" */ | |||
| /*-Specials-*/ | |||
| define symbol __ICFEDIT_intvec_start__ = 0x08000000; | |||
| /*-Memory Regions-*/ | |||
| define symbol __ICFEDIT_region_ROM_start__ = 0x08000000 ; | |||
| define symbol __ICFEDIT_region_ROM_end__ = 0x0801FFFF; | |||
| define symbol __ICFEDIT_region_RAM_start__ = 0x20000000; | |||
| define symbol __ICFEDIT_region_RAM_end__ = 0x20004FFF; | |||
| /*-Sizes-*/ | |||
| define symbol __ICFEDIT_size_cstack__ = 0x400; | |||
| define symbol __ICFEDIT_size_heap__ = 0x200; | |||
| /**** End of ICF editor section. ###ICF###*/ | |||
| define memory mem with size = 4G; | |||
| define region ROM_region = mem:[from __ICFEDIT_region_ROM_start__ to __ICFEDIT_region_ROM_end__]; | |||
| define region RAM_region = mem:[from __ICFEDIT_region_RAM_start__ to __ICFEDIT_region_RAM_end__]; | |||
| define block CSTACK with alignment = 8, size = __ICFEDIT_size_cstack__ { }; | |||
| define block HEAP with alignment = 8, size = __ICFEDIT_size_heap__ { }; | |||
| initialize by copy { readwrite }; | |||
| do not initialize { section .noinit }; | |||
| place at address mem:__ICFEDIT_intvec_start__ { readonly section .intvec }; | |||
| place in ROM_region { readonly }; | |||
| place in RAM_region { readwrite, | |||
| block CSTACK, block HEAP }; | |||
| @ -1,31 +0,0 @@ | |||
| /*###ICF### Section handled by ICF editor, don't touch! ****/ | |||
| /*-Editor annotation file-*/ | |||
| /* IcfEditorFile="$TOOLKIT_DIR$\config\ide\IcfEditor\cortex_v1_0.xml" */ | |||
| /*-Specials-*/ | |||
| define symbol __ICFEDIT_intvec_start__ = 0x20000000; | |||
| /*-Memory Regions-*/ | |||
| define symbol __ICFEDIT_region_ROM_start__ = 0x20000000 ; | |||
| define symbol __ICFEDIT_region_ROM_end__ = 0x200013FF; | |||
| define symbol __ICFEDIT_region_RAM_start__ = 0x20001400; | |||
| define symbol __ICFEDIT_region_RAM_end__ = 0x20004FFF; | |||
| /*-Sizes-*/ | |||
| define symbol __ICFEDIT_size_cstack__ = 0x400; | |||
| define symbol __ICFEDIT_size_heap__ = 0x200; | |||
| /**** End of ICF editor section. ###ICF###*/ | |||
| define memory mem with size = 4G; | |||
| define region ROM_region = mem:[from __ICFEDIT_region_ROM_start__ to __ICFEDIT_region_ROM_end__]; | |||
| define region RAM_region = mem:[from __ICFEDIT_region_RAM_start__ to __ICFEDIT_region_RAM_end__]; | |||
| define block CSTACK with alignment = 8, size = __ICFEDIT_size_cstack__ { }; | |||
| define block HEAP with alignment = 8, size = __ICFEDIT_size_heap__ { }; | |||
| initialize by copy { readwrite }; | |||
| do not initialize { section .noinit }; | |||
| place at address mem:__ICFEDIT_intvec_start__ { readonly section .intvec }; | |||
| place in ROM_region { readonly }; | |||
| place in RAM_region { readwrite, | |||
| block CSTACK, block HEAP }; | |||
| @ -1,35 +0,0 @@ | |||
| # This is an F103C8T6_DIGI_USB board with a single STM32F103C8Tx chip | |||
| # | |||
| # Generated by System Workbench for STM32 | |||
| # Take care that such file, as generated, may be overridden without any early notice. Please have a look to debug launch configuration setup(s) | |||
| source [find interface/stlink.cfg] | |||
| set WORKAREASIZE 0x5000 | |||
| transport select "hla_swd" | |||
| set CHIPNAME STM32F103C8Tx | |||
| set BOARDNAME F103C8T6_DIGI_USB | |||
| # CHIPNAMES state | |||
| set CHIPNAME_CPU0_ACTIVATED 1 | |||
| # Enable debug when in low power modes | |||
| set ENABLE_LOW_POWER 1 | |||
| # Stop Watchdog counters when halt | |||
| set STOP_WATCHDOG 1 | |||
| # STlink Debug clock frequency | |||
| set CLOCK_FREQ 8000 | |||
| # use software system reset | |||
| reset_config none | |||
| set CONNECT_UNDER_RESET 0 | |||
| # BCTM CPU variables | |||
| source [find target/stm32f1x.cfg] | |||
| @ -1,35 +0,0 @@ | |||
| # This is an F103C8T6_DIGI_USB board with a single STM32F103C8Tx chip | |||
| # | |||
| # Generated by System Workbench for STM32 | |||
| # Take care that such file, as generated, may be overridden without any early notice. Please have a look to debug launch configuration setup(s) | |||
| source [find interface/stlink.cfg] | |||
| set WORKAREASIZE 0x5000 | |||
| transport select "hla_swd" | |||
| set CHIPNAME STM32F103C8Tx | |||
| set BOARDNAME F103C8T6_DIGI_USB | |||
| # CHIPNAMES state | |||
| set CHIPNAME_CPU0_ACTIVATED 1 | |||
| # Enable debug when in low power modes | |||
| set ENABLE_LOW_POWER 1 | |||
| # Stop Watchdog counters when halt | |||
| set STOP_WATCHDOG 1 | |||
| # STlink Debug clock frequency | |||
| set CLOCK_FREQ 8000 | |||
| # use software system reset | |||
| reset_config none | |||
| set CONNECT_UNDER_RESET 0 | |||
| # BCTM CPU variables | |||
| source [find target/stm32f1x.cfg] | |||
| @ -1,48 +1,56 @@ | |||
| # VP-Digi | |||
| VP-Digi is a functional, cheap, easy to assemble and configure STM32-based APRS digipeater controller with built-in KISS modem. | |||
| Polska wersja tego pliku dostępna jest [tutaj](README_pl.md). | |||
| * 1200 Bd Bell 202 modem (VHF APRS standard) | |||
| * R2R or PWM signal generation | |||
| **VP-Digi** is a functional, affordable, easy-to-assemble, and configure STM32-based APRS digipeater controller with a built-in KISS modem. | |||
| * Multiple modems: | |||
| * 1200 Bd AFSK Bell 202 (VHF standard) | |||
| * 300 Bd AFSK Bell 103 (HF standard) | |||
| * 9600 Bd GFSK G3RUH (UHF standard) | |||
| * 1200 Bd AFSK V.23 | |||
| * PWM (or deprecated R2R) signal generation | |||
| * Analog-digital busy channel detection (data carrier detection) | |||
| * AX.25 coder/decoder designed for APRS frames | |||
| * digipeater: 4 settable n-N aliases, 4 simple aliases, viscous delay (known from aprx) or direct only, black and white list | |||
| * AX.25 coder/decoder | |||
| * FX.25 (AX.25 with error correction) coder/decoder, fully compatible with [Direwolf](https://github.com/wb2osz/direwolf) and [UZ7HO Soundmodem](http://uz7.ho.ua/packetradio.htm) | |||
| * Digipeater: 4 settable n-N aliases, 4 simple aliases, viscous delay (known from aprx) or direct only, black and white list | |||
| * 8 independent beacons | |||
| * KISS mode (can be used as an ordinary modem with UI-View, APRSIS32, XASTIR etc.) | |||
| * USB and 2 UARTs: independent, running in KISS, monitor or configuration mode | |||
| * KISS mode (can be used as an ordinary Packet Radio, Winlink, APRS, etc. modem) | |||
| * USB and 2 UARTs: independent, running in KISS, monitor, or configuration mode | |||
| ## Download and setup | |||
| The latest compiled firmware can be downloaded [here](https://github.com/sq8vps/vp-digi/releases).\ | |||
| Full documentation can be found [here](doc/manual.md). | |||
| ## Updating to 2.0.0+ on older hardware | |||
| Since version 2.0.0, the component values have changed to provide support for faster modulations (9600 Bd). If you want to use these, some components must be replaced. For more information, refer to the [manual](doc/manual.md). | |||
| ## Description, schematic, instructions | |||
| If you are not interested in source code, this repository is not for you. You can find full project description, schematics, compiled firmware and instructions [on my website](https://sq8l.pzk.pl/index.php/vp-digi-cheap-and-functional-aprs-digipeater-controller-with-kiss-modem/). | |||
| <<<<<<< HEAD | |||
| The user manual and technical description are available [here](doc/manual.md). | |||
| ======= | |||
| ## Source code usage | |||
| The firmware was written using System Workbench for STM32 (SW4STM32) and you should be able to import this repository directly to the IDE. The source code is publicly available since version 1.2.0. | |||
| >>>>>>> e9a5ebd2c6fc83adbfacb614029274ed01491d16 | |||
| ## Source code | |||
| The firmware was written using STM32CubeIDE, and you should be able to import this repository directly into the IDE. You can get the source code using: | |||
| ```bash | |||
| git clone https://github.com/sq8vps/vp-digi.git | |||
| ``` | |||
| Since version 2.0.0, you will also need to get the appropriate submodule ([LwFEC](https://github.com/sq8vps/lwfec) for Reed-Solomon FEC): | |||
| ```bash | |||
| git submodule init | |||
| git submodule update | |||
| ``` | |||
| Since version 2.0.0, there is also a possibility to build the firmware with or without FX.25 protocol support. The `ENABLE_FX25` symbol must be defined to enable FX.25 support. On STM32CubeIDE, this can be done under *Project->Properties->C/C++ Build->Settings->Preprocessor->Defined symbols*. | |||
| ## Technical description | |||
| The project was designed to be running on a Blue Pill board (STM32F103C8T6) with 8MHz crystal. The firmware was written using only register operations (with ST headers) and CMSIS libraries. The HAL is there only for USB. The code is (quite) extensively commented where needed, so it shouldn't be very hard to understand. | |||
| ### Demodulator | |||
| There are two demodulators (and decoders) running in parallel to provide better efficiency. The signal is sampled at 38400Hz (32 samples per symbol) by DMA. The interrupt is generated after receiving 4 samples and the samples are decimated. Then they are passed through a preemphasis/deemphasis filter (if enabled) which equalizes tone amplitudes. Filtered samples are multiplied by locally generated mark and space tones (their I and Q parts - cosine and sine). This gives a correlation factor between the input signal and each tone. In the meanwhile an unfiltered symbol is produced to drive the data carrier detection PLL. The difference of correlation factors is the new sample and is passed through a low pass filter to eliminate noise. Filtered samples are compared to zero and the demodulated symbol is sent to bit recovery mechanism. | |||
| ### Bit recovery (and NRZI decoder) | |||
| Bit recovery mechanism is based on a digital PLL. The PLL is nominally running at 1200Hz (=1200 Baud). The symbol change should occur near PLL counter zero, so that the counter overflows in the middle of the symbol and the symbol value is sampled. With every symbol change the counter is multiplied by a <1 factor to bring it closer to zero, keeping the PLL and incoming signal in phase. The DCD signal is multiplexed from both modems. Explained more in [modem.c](Src/drivers/modem.c). Sampled symbol is decoded by NRZI decoder and sent to AX.25 layer. | |||
| ### AX.25 decoding | |||
| AX.25 decoder is quite standard. CRC, PID and Control Byte are checked and both modem paths are multiplexed to produce only one output frame. | |||
| ### Data carrier detection | |||
| DCD uses an analog-digital approach: based on PLL, but working on a digital unfiltered symbol stream. The PLL works in the same way as bit recovery PLL, except that there is a special DCD pulse counting mechanism implemented, explained in [modem.c](Src/drivers/modem.c). This approach seems to be far more effective than a typical, digital, AX.25-based detection. | |||
| ### AX.25 encoding | |||
| AX.25 encoder is also quite simple. It can handle multiple frames in a row (limited by buffer length). Every transmission starts with preamble flags, then header flags, actual data, CRC, footer/separating flags, actual data, CRC, footer/separating flags... and tail flags. Raw bits are requested by the modulator. | |||
| ### Modulator (and NRZI encoder) | |||
| The NRZI encoder runs at exactly 1200Hz (=1200 Baud) and requests bits from the AX.25 encoder. Bits are encoded to symbols and the DAC sampling timer interval is set depending on symbol value. Because of that there is only one sine table used. For 1200Hz tone the timer interval is larger than for 2200 Hz tone - the sampling frequency is changed to change the output signal frequency. An array index is always kept so that the output signal phase is continuous. | |||
| ## Using VP-Digi code in your project | |||
| I would love to hear about projects which implement VP-Digi source code. If you are making one, let me know at sq8vps(at)gmail.com. | |||
| ## References | |||
| The project took a lot of time to finish, but now it's probably the most effective, publicly available, STM32-based modem and the most customizable microcontroller-based APRS digipeater. I would like to mention some resources I found really useful or inspiring: | |||
| * [multimon-ng](https://github.com/EliasOenal/multimon-ng) - general demodulator idea (correlation) | |||
| * [BeRTOS](https://github.com/develersrl/bertos) - AX.25 decoder | |||
| * [Forum thread by SP8EBC](http://forum.aprs.pl/index.php?topic=2086.0) - inspiration | |||
| * [DireWolf](https://github.com/wb2osz/direwolf) - PLL bit recovery idea | |||
| * [A High-Performance Sound-Card AX.25 Modem](https://www.tau.ac.il/~stoledo/Bib/Pubs/QEX-JulAug-2012.pdf) - preemphasis and low pass filtering idea | |||
| * [UZ7HO Soundmodem](http://uz7.ho.ua/packetradio.htm) - PLL-based DCD idea | |||
| ## Contributing | |||
| All contributions are appreciated, but please keep the code reasonably clean. Also, please make sure that the firmware is working well before creating a pull request. | |||
| All contributions are appreciated. | |||
| ## License | |||
| The project is licensed under the GNU GPL v3 license (see [LICENSE](LICENSE)). | |||