Демонстрационная прошивка отладочного комплекта МТС NB-IoT
board_support_api.c
См. документацию.
1 #include "board_support_api.h"
2 
9 volatile uint8_t LSE_failed=0;
10 volatile uint32_t uptime_counter=0;
11 volatile uint32_t CYCLES_PER_1SEC=0;
12 volatile uint32_t button_press_counter=0;
13 volatile uint8_t button_press_detected=0;
14 
24 int _write(int fd, const void *buf, size_t count)
25 {
26  size_t k;
27 
28  for (k=0; k<count; k++)
29  {
30  UART_SendByte(USART1,((uint8_t *)buf)[k]);
31  }
32 
33  return count;
34 }
35 
39 int _read(int fd, const void *buf, size_t count)
40 {
41  size_t k;
42 
43  for (k=0; k<count; k++)
44  {
45  ((uint8_t *)buf)[k] = UART_WaitRxByte(USART1);
46 #if ECHO_INPUT_CHARS == 1
47  UART_SendByte(USART1,((uint8_t *)buf)[k]); //Echo
48  #warning Firmware compiled with console echo option turned ON; this may cause problems with rapid input.
49 #endif
50  }
51 
52  return count;
53 }
54 
55 void TIM9_IRQHandler(void)
56 {
57  if (TIM9->SR & TIM_SR_CC1IF)
58  {
59  uptime_counter++;
60 
61  TIM9->CCR1 += TMR_CNT_1MSEC;
62  }
63 
64  if (TIM9->SR & TIM_SR_CC2IF)
65  {
66  //Button is active low
67  if ((!(GPIOC->IDR & PIN_MASK(USER_SW_PC))) && (!button_press_detected))
68  {
69  button_press_counter++;
70  }
71 
72  if ((GPIOC->IDR & PIN_MASK(USER_SW_PC)) && (!button_press_detected) && (button_press_counter!=0))
73  {
74  button_press_detected = 1;
75  }
76 
77  TIM9->CCR2 += BTN_POLL_PERIOD;
78  }
79 
80  TIM9->SR = 0;
81 }
82 
83 uint32_t get_uptime_ms(void)
84 {
85  return uptime_counter;
86 }
87 
88 void delay_ms(uint32_t N)
89 {
90  uint32_t wait_start;
91 
92  wait_start = get_uptime_ms();
93 
94  while ((get_uptime_ms() - wait_start)<N)
95  {
96  }
97 }
98 
99 uint32_t get_button_press(void)
100 {
101  uint32_t tmp;
102 
103  if (button_press_detected)
104  {
105  tmp = button_press_counter;
106  button_press_counter = 0;
107  button_press_detected = 0;
108 
109  return tmp;
110  }
111  else
112  {
113  return 0;
114  }
115 }
116 
117 void switch_LED(uint8_t state)
118 {
119  if (state!=0)
120  {
121  GPIOA->BSRRH = PIN_MASK(USER_LED_PA);
122  }
123  else
124  {
125  GPIOA->BSRRL = PIN_MASK(USER_LED_PA);
126  }
127 }
128 
130 {
131  volatile uint32_t k;
132 
133  //Notice that this signal gets inverted on board.
134  GPIOC->BSRRL = PIN_MASK(NB_PWR_ON_PC);
135 
136  for (k=0; k<(CYCLES_PER_1SEC/2); k++)
137  {
138  }
139 
140  GPIOC->BSRRH = PIN_MASK(NB_PWR_ON_PC);
141 }
142 
143 void FLASH_WriteEEPROM(volatile uint32_t *eeprom_ptr,uint32_t *data_ptr,uint16_t data_size_words)
144 {
145  volatile uint16_t k;
146 
147  FLASH->PEKEYR = 0x89ABCDEF;
148  FLASH->PEKEYR = 0x02030405;
149 
150  for (k=0; k<data_size_words; k++)
151  {
152  eeprom_ptr[k] = data_ptr[k];
153  }
154 
155  FLASH->PECR = FLASH_PECR_PELOCK;
156 }
157 
159 {
160  //The easiest way to write to EEPROM area is by word at once
161  FLASH_WriteEEPROM(EEPROM_START_ADDRESS,(uint32_t *)data,sizeof(device_setup_data_t)/4);
162 }
163 
165 {
166  //Unlike writing, reading EERPOM area can be performed byte by byte, so no problem with memcpy()
167  memcpy(data,EEPROM_START_ADDRESS,sizeof(device_setup_data_t));
168 }
169 
170 void apply_backspace(uint8_t *str,uint16_t max_length)
171 {
172  uint16_t ptr_r;
173  uint16_t ptr_w;
174 
175  ptr_r = 0;
176  ptr_w = 0;
177 
178  while ((str[ptr_r]!=0) && (ptr_r<max_length))
179  {
180  if (str[ptr_r]==0x7F)
181  {
182  /* Backspace found */
183  if (ptr_w>0)
184  {
185  /* Each backspace shifts the write pointer one symbol left */
186  ptr_w--;
187  }
188  }
189  else
190  {
191  /* Symbols after the backspace character are written to the position, corrected by backspace sequence,
192  effectively replacing the old input. */
193  if (ptr_r!=ptr_w)
194  {
195  str[ptr_w] = str[ptr_r];
196  }
197 
198  ptr_w++;
199  }
200 
201  ptr_r++;
202  }
203 
204  str[ptr_w] = 0;
205 }
206 
207 void init_board(void)
208 {
209  volatile uint32_t safety_counter;
210  uint32_t calib_start;
211 
212  /*
213  Clock system init
214  */
215 
216  //The STM32L152RE uses MSI clock at 2.097 MHz at startup. Switching clock to 16 MHz HSI to use I2C more conveniently.
217  RCC->CR |= RCC_CR_HSION;
218 
219  safety_counter=0;
220  while ((!(RCC->CR & RCC_CR_HSIRDY)) && (safety_counter<OSC_STARTUP_CYCLES_MAX))
221  {
222  safety_counter++;
223  }
224 
225  //Switch clock to HSI; after this write clock will be switched automatically after some time.
226  RCC->CFGR |= RCC_CFGR_SW_HSI;
227 
228  /*
229  Peripheral clock enable
230  */
231  RCC->AHBENR |= RCC_AHBENR_GPIOAEN | RCC_AHBENR_GPIOBEN | RCC_AHBENR_GPIOCEN;
232  RCC->APB1ENR |= RCC_APB1ENR_I2C1EN | RCC_APB1ENR_USART2EN | RCC_APB1ENR_USART3EN;
233  RCC->APB2ENR |= RCC_APB2ENR_TIM9EN | RCC_APB2ENR_TIM10EN | RCC_APB2ENR_USART1EN;
234 
235  /*
236  USART1 is used for console I/O
237  USART2 is used to communicate with the GNSS module
238  */
239  GPIOA->MODER |= PIN_MODE(USART2_RX_PA,MODE_AF) |
241  PIN_MODE(USART1_RX_PA,MODE_AF) |
243  PIN_MODE(USER_LED_PA,MODE_GPOUT) |
244  PIN_MODE(NB_VINT_PA,MODE_GPIN);
245  GPIOA->AFR[0] |= PIN_AFRL(USART2_RX_PA,USART123_AF_NO) |
247  GPIOA->AFR[1] |= PIN_AFRH(USART1_RX_PA,USART123_AF_NO) |
249 
252  NVIC_EnableIRQ(USART2_IRQn);
253 
254  //To remedy possible lags
255  setbuf(stdin,NULL);
256  setbuf(stdout,NULL);
257 
258  printf("\r\n\r\nBoard started, console initialized.\r\n");
259 
260  RCC->APB1ENR |= RCC_APB1ENR_PWREN;
261 
262  //Check if LSE is already running; if not, start it in order to be able to use AWU
263  if (!(RCC->CSR & RCC_CSR_LSERDY))
264  {
265  printf("Starting LSE...\r\n");
266  //To enable LSE for AWU, we have first to deal with RCC registers protection, for it is controlled from RTC domain.
267  PWR->CR |= PWR_CR_DBP;
268  RTC->WPR = 0xCA;
269  RTC->WPR = 0x53;
270  RCC->CSR |= RCC_CSR_LSEON;
271 
272  safety_counter=0;
273  while ((!(RCC->CSR & RCC_CSR_LSERDY)) && (safety_counter<OSC_STARTUP_CYCLES_MAX))
274  {
275  safety_counter++;
276  }
277 
278  if (safety_counter>=OSC_STARTUP_CYCLES_MAX)
279  {
280  LSE_failed=1;
281  }
282  else
283  {
284  LSE_failed=0;
285  }
286 
287  //Turn RTC clock ON and configure it to be LSE
288  RCC->CSR |= RCC_CSR_RTCEN | RCC_CSR_RTCSEL_0;
289 
290  RTC->WPR = 0x00; //Reactivate write protection
291  PWR->CR &= ~PWR_CR_DBP;
292  }
293  else
294  {
295  LSE_failed=0;
296  printf("Found LSE already running.\r\n");
297  }
298 
299  if (LSE_failed)
300  {
301  printf("(!) Failed to start LSE.\r\n");
302  }
303 
304 #ifdef CONFIGURE_CLOCK_OUT
305 
306 #if defined(OBSERVE_LSE) && defined(OBSERVE_SYSCLK)
307  #error Only one clock source can be monitored at once
308 #else
309 
310 #ifdef OBSERVE_LSE
311  RCC->CFGR |= RCC_CFGR_MCO_LSE;
312  #warning Pin PA8 (Arduino-compatible: D7) is configured as MCO for LSE clock observation
313  printf("NOTICE: PA8 (Arduino D7) is configured to output LSE clock.\r\n");
314 #endif
315 #ifdef OBSERVE_SYSCLK
316  RCC->CFGR |= RCC_CFGR_MCO_SYSCLK;
317  #warning Pin PA8 (Arduino-compatible: D7) is configured as MCO for SYSCLK clock observation
318  printf("NOTICE: PA8 (Arduino D7) is configured to output SYSCLK.\r\n");
319 #endif
320 
321  GPIOA->MODER |= PIN_MODE(8,MODE_AF);
322  GPIOA->AFR[1] |= PIN_AFRH(8,0);
323 #endif
324 #endif
325 
326  /*
327  I2C1 is used for accelerometer and temperature sensor
328  */
329  GPIOB->BSRRH = PIN_MASK(NB_RTS_PB); //Set RTS low to enable USART for module revisions 00 and 01
330  GPIOB->MODER |= PIN_MODE(I2C1_SCL_PB,MODE_AF) | PIN_MODE(I2C1_SDA_PB,MODE_AF) | PIN_MODE(NB_RTS_PB,MODE_GPOUT);
331  GPIOB->OTYPER |= PIN_MASK(I2C1_SCL_PB) | PIN_MASK(I2C1_SDA_PB);
332  GPIOB->AFR[1] |= PIN_AFRH(I2C1_SCL_PB,I2C1_AF_NO) | PIN_AFRH(I2C1_SDA_PB,I2C1_AF_NO);
333 
335 
336  printf("I2C configured.\r\n");
337 
338  /*
339  USART3 is used for communication with the NB-IoT module
340  */
341 
342  //NB-IoT module PWR_ON and RESET_N inactive
343  GPIOC->BSRRH = PIN_MASK(NB_PWR_ON_PC) | PIN_MASK(NB_RESET_PC);
344  GPIOC->MODER |= PIN_MODE(USART3_TX_PC,MODE_AF) |
345  PIN_MODE(USART3_RX_PC,MODE_AF) |
348  PIN_MODE(USER_SW_PC,MODE_GPIN);
349  GPIOC->AFR[1] |= PIN_AFRH(USART3_TX_PC,USART3_AF_NO) | PIN_AFRH(USART3_RX_PC,USART3_AF_NO);
350 
352  NVIC_EnableIRQ(USART3_IRQn);
353 
354  printf("USART3 configured.\r\n");
355 
356  /*
357  TIM9 is used for an uptime counter and button state check
358  */
359 
360  TIM9->CCR1 = TMR_CNT_1MSEC;
361  TIM9->CCR2 = BTN_POLL_PERIOD;
362  TIM9->PSC = TMR_PRESC;
363  TIM9->DIER = TIM_DIER_CC1IE | TIM_DIER_CC2IE;
364  TIM9->CR1 = TIM_CR1_ARPE | TIM_CR1_CEN;
365  TIM9->EGR = TIM_EGR_UG;
366 
367  NVIC_EnableIRQ(TIM9_IRQn);
368 
369  printf("Uptime timer started.\r\n");
370 
371  printf("Calibrating delay loop value...\r\n");
372  CYCLES_PER_1SEC = 0;
373  calib_start = get_uptime_ms();
374  while ((get_uptime_ms() - calib_start)<1000)
375  {
376  CYCLES_PER_1SEC++;
377  }
378 
379  printf("%d cycles per second.\r\n",CYCLES_PER_1SEC);
380 }
CYCLES_PER_1SEC
volatile uint32_t CYCLES_PER_1SEC
Калиброванное значение: количество итераций пустого цикла за 1 секунду при текущей тактовой частоте....
Definition: board_support_api.c:11
USART123_AF_NO
#define USART123_AF_NO
Номер альтернативной функции, соответствующей USART1/2/3, согласно документации
Definition: board_pins.h:33
OSC_STARTUP_CYCLES_MAX
#define OSC_STARTUP_CYCLES_MAX
Definition: board_support_api.h:74
PIN_MASK
#define PIN_MASK(pin_no)
Преобразует номер бита в битовую маску
Definition: port_macros.h:31
_read
int _read(int fd, const void *buf, size_t count)
Переопределение функции работы со входным потоком для использования scanf() с USART2.
Definition: board_support_api.c:39
get_uptime_ms
uint32_t get_uptime_ms(void)
Возвращает время с момента начала работы прошивки
Definition: board_support_api.c:83
_write
int _write(int fd, const void *buf, size_t count)
Переопределение функции работы с выходным потоком для использования printf() c USART2.
Definition: board_support_api.c:24
USART1_TX_PA
#define USART1_TX_PA
USART1 используется для реализации вывода printf()
Definition: board_pins.h:27
FLASH_WriteEEPROM
void FLASH_WriteEEPROM(volatile uint32_t *eeprom_ptr, uint32_t *data_ptr, uint16_t data_size_words)
Запись в EEPROM.
Definition: board_support_api.c:143
TMR_PRESC
#define TMR_PRESC
Definition: board_support_api.h:80
PIN_AFRH
#define PIN_AFRH(pin_no, af_no)
Формирует битовую маску для записи в регистр AFRH.
Definition: port_macros.h:40
UART_WaitRxByte
uint8_t UART_WaitRxByte(USART_TypeDef *uart_inst)
Ожидает приема байта через указанный USART.
Definition: uart_api.c:30
LSE_failed
volatile uint8_t LSE_failed
В случае, если генератор LSE запустить не удалось, значение этой переменной будет ненулевым.
Definition: board_support_api.c:9
GNSS_BAUDRATE
#define GNSS_BAUDRATE
По умолчанию модули EVA M8 выдают данные на скорости 9600 бит/с
Definition: board_support_api.h:42
DEFAULT_CLOCK_FREQ
#define DEFAULT_CLOCK_FREQ
Значение тактовой частоты, на которой работает контроллер
Definition: board_support_api.h:38
UART_SendByte
void UART_SendByte(USART_TypeDef *uart_inst, uint8_t b)
Посылает байт через указанный USART.
Definition: uart_api.c:9
init_i2c
void init_i2c(I2C_TypeDef *i2c_inst, uint32_t sys_clk)
Выполняет настройку модуля I2C для работы на стандартной частоте SDA, равной 100 кГц.
Definition: i2c_api.c:310
device_setup_data_t
Структура, хранящая настройки работы основного демонстрационного приложения
Definition: board_support_api.h:99
MODE_GPIN
#define MODE_GPIN
Режим цифрового входа
Definition: port_macros.h:17
PIN_MODE
#define PIN_MODE(pin_no, pin_mode)
Формирует битовую маску для записи в регистр MODER.
Definition: port_macros.h:28
recall_device_settings
void recall_device_settings(device_setup_data_t *data)
Загрузка настроек устройства из области EEPROM.
Definition: board_support_api.c:164
USART2_TX_PA
#define USART2_TX_PA
USART2 используется для приема данных от модуля GNSS.
Definition: board_pins.h:30
init_board
void init_board(void)
Функция выполняет настройку тактирования и инициализацию периферии, используемой демонстрационным при...
Definition: board_support_api.c:207
delay_ms
void delay_ms(uint32_t N)
Приостанавливает выполнение программы на заданное время. Значение задержки задается в миллисекундах.
Definition: board_support_api.c:88
NB_PWR_ON_PC
#define NB_PWR_ON_PC
Вывод порта, включающий питание модуля NB-IoT.
Definition: board_pins.h:46
PIN_AFRL
#define PIN_AFRL(pin_no, af_no)
Формирует битовую маску для записи в регистр AFRL.
Definition: port_macros.h:36
SARA_R410M_DEFAULT_BAUDRATE
#define SARA_R410M_DEFAULT_BAUDRATE
Скорость обмена с радиомодулем
Definition: board_support_api.h:49
MODE_GPOUT
#define MODE_GPOUT
Режим цифрового выхода
Definition: port_macros.h:19
BTN_POLL_PERIOD
#define BTN_POLL_PERIOD
Интервал опроса кнопки, выраженный в отсчетах таймера.
Definition: board_support_api.h:84
get_button_press
uint32_t get_button_press(void)
Возвращает время удержания кнопки нажатой с момента предыдущего вызова функции.
Definition: board_support_api.c:99
NB_RESET_PC
#define NB_RESET_PC
Вывод порта, перезагружающий модуль NB-IoT.
Definition: board_pins.h:48
SARA_R410_PWR_ON_pulse
void SARA_R410_PWR_ON_pulse(void)
Генерирует импульс низкого уровня продолжительностью примерно 500 мс на линии PWR_ON радиомодуля.
Definition: board_support_api.c:129
USART3_TX_PC
#define USART3_TX_PC
USART3 подключен к модулю NB-IoT.
Definition: board_pins.h:36
switch_LED
void switch_LED(uint8_t state)
Включает или выключает светодиод на плате.
Definition: board_support_api.c:117
store_device_settings
void store_device_settings(device_setup_data_t *data)
Сохранение настроек устройства в область EEPROM.
Definition: board_support_api.c:158
init_uart
void init_uart(USART_TypeDef *uart_inst, const uint32_t baudrate, const uint32_t sys_clk, uint8_t enable_rxne_int)
Настройка модуля USART для работы с указанной скоростью.
Definition: uart_api.c:39
CONSOLE_BAUDRATE
#define CONSOLE_BAUDRATE
Значение скорости обмена для консоли (вывод printf() через USART1 и встроенный в плату USB-UART конве...
Definition: board_support_api.h:40
board_support_api.h
I2C1_AF_NO
#define I2C1_AF_NO
Номер альтернативной функции, соответствующей I2C1, согласно документации
Definition: board_pins.h:43
MODE_AF
#define MODE_AF
Режим альтернативной функции
Definition: port_macros.h:21
apply_backspace
void apply_backspace(uint8_t *str, uint16_t max_length)
Модифицирует строку с учетом символов backspace.
Definition: board_support_api.c:170
TMR_CNT_1MSEC
#define TMR_CNT_1MSEC
Количество отсчетов таймера за 1 мс.
Definition: board_support_api.h:82