Кто любит RISC в жизни, заходим, не стесняемся.
Ответить

Re: Stm32 с чего начать изучение...

Ср янв 26, 2022 01:01:28

ПростоНуб, ассемблер - это язык высокого уровня, "специалист" я программировал тумблерами, вводя двоичный код.:)

Re: Stm32 с чего начать изучение...

Ср янв 26, 2022 01:27:58

linkov1959, сэр прямо извращенец. i8080 и Z80, когда еще не было ассеблера для ZX Spectrum, я программировал все равно на ассемблере, просто сделав себе макробиблиотеку кроссассемблера для ассемблера ЕС ЭВМ. Выводил на перфоленту, а с нее уже самодельным считывателем и ручным протягиванием перфоленты через него - прошивал РФ-ки.
Вот на EC 1033 тумблерами простейшие канальные программы вводил. Но там без вариантов было. Если система не грузится из-за зависшей дисковой стойки, то иначе ее не протолкнуть. А по питанию передергивать - себе дороже. Включение ЕС 1033 - это всегда была целая история, причем, нередко, с заменой сдохших при включении ТЭЗов. Потому месяцами не выключали ее. Когда появились ЕС-1035, ЕС-1045 и ЕС-1061 - это было уже счастье. У них уже был сервисный процессор, с которым можно было общаться через Consul или даже дисплей.

Re: Stm32 с чего начать изучение...

Ср янв 26, 2022 08:14:05

ПростоНуб писал(а):в IT, если даже всего год не учиться ничему новому, квалификацию теряешь заметно
так я и потерял... профессионально (т.е. по должности) я программировал (недолго) еще в те времена, когда написание программ на ассемблере для MS DOS было вполне естественным... а потом увы.

Re: Stm32 с чего начать изучение...

Ср янв 26, 2022 09:02:23

Мне вот ночью приснилось, что при выполнении кода из RAM, например, при отладке, сегмент данных находится сразу на своём месте
Код:
   .data :
   {
      . = ALIGN(4);
      _sdata = .;
      *(.data)
      *(.data*)
      . = ALIGN(4);
      _edata = .;
   } > SRAM
и его не надо копировать в стартапе. То есть, правильнее в стартапе вот так
Код:
#ifndef __DEBUG_SRAM__   
  extern uint32_t _sidata[], _sdata[], _edata[];
  for (volatile uint32_t *pSrc = _sidata, *pDst = _sdata; pDst != _edata; *pDst ++= *pSrc++) ;
#endif

Re: Stm32 с чего начать изучение...

Ср янв 26, 2022 20:40:28

ПростоНуб, А ещё, извращенцы стирали РФки сваркой!

Re: Stm32 с чего начать изучение...

Ср янв 26, 2022 20:51:57

linkov1959, тогда уж солнышком. Но некоторые пытались это делать через оконное стекло, забыв, что оно ультрафиолет не пропускает )))
Но это реально изврат, так как люминисцентные УФ лампы тогда были вполне доступны в продаже. Великоваты, конечно, так как предназначались для загара или в медицинских целях. Но вполне пригодны для стирания РФ-ок.

Re: Stm32 с чего начать изучение...

Ср янв 26, 2022 22:21:38

ПростоНуб писал(а):тогда уж солнышком.
Пробовал. Это долго. Понадобилось около 2-ух месяцев нахождения на солнце.
Лучше уж
linkov1959 писал(а):сваркой
:))) :)))

Re: Stm32 с чего начать изучение...

Чт янв 27, 2022 05:26:05

Мурик, в полярную ночь что ли пробовали или сквозь оконное стекло? В ясную погоду под летним крымским солнышком большинство за день стирались, хотя изредка попадались экземпляры, которые приходилось неделю держать до сплошного 0xFF.

P.S. На Роман-коше стирать не пробовал. Подозреваю, что на высоте в полтора километра за несколько часов бы все стерлись )

Re: Stm32 с чего начать изучение...

Чт янв 27, 2022 09:15:26

VladislavS, ты что ты дал, там стартап какой-то скудный
Код:
/*----------
  Reset Handler called on controller reset
 *----------*/
void Reset_Handler(void)
{
  SystemInit();                             /* CMSIS System Initialization */
  __PROGRAM_START();                        /* Enter PreMain (C library entry point) */
}
не говоря уж про SystemInit(). И где само копирование? Самому ручками прописывать?
VladislavS писал(а):что при выполнении кода из RAM
а я то думал, но по чему из ram толком ни чего не работает.

Re: Stm32 с чего начать изучение...

Чт янв 27, 2022 10:34:18

а я то думал, но по чему из ram толком ни чего не работает.
Вывод неверный. Копирование данных самих в себя только время лишнее занимает и ничего в работе прошивки не меняет.

Re: Stm32 с чего начать изучение...

Чт янв 27, 2022 12:50:23

Dimon456 писал(а):И где само копирование? Самому ручками прописывать?

Видимо, внутри __PROGRAM_START(). Это ведь Enter PreMain (C library entry point). Там создаются и инициализируются начальными значениями глобальные и локальные статические данные в RAM-памяти.

Re: Stm32 с чего начать изучение...

Пт апр 22, 2022 19:36:27

Здравствуйте, друзья!
Пересаживаюсь с АВР на СТМ, изучаю, вот в голову залезла бестолковая идея: сделать функцию расчёта частоты работы МК.
По сути - всё изветно: кварц, все прескалеры, но... Идея сделать расчёт универсальным, а не просто взять известные цифры и перемножить. То есть, сделать функцию расчёта по параметрам, заданым в SystemClock_Config();
Но как вытянуть численное значение из строки RCC_OscInitStruct.PLL.PLLN = 168; ?
И, в продолжение, есть параметры, который описаны так: RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;, тут вопрос как их запихнуть в IF для сравнения и последующего приравнивания некой переменной числа.
Как знаю - попробовал, не работает. Прошу помощи.

Заранее спасибо и простите мою неграмотность :)

Re: Stm32 с чего начать изучение...

Пт апр 22, 2022 19:49:24

Все делители в конце концов ложатся в регистры RCC. Оттуда их можно читать. Только пустое это. Зачем вычислять то что вы сами же и задаёта?

Re: Stm32 с чего начать изучение...

Пт апр 22, 2022 20:23:40

делать функцию расчёта частоты работы МК.

Она уже есть! Найдите поиском ф-цию SystemCoreClockUpdate. Она входит в стандартную поставку и генерируется вместе с созданием проекта.
Эта функция обновляет глобальную переменную SystemCoreClock, которая может использоваться в выражениях для задания частотозависимых интервалов. Например при настройке таймера.
Необходимость в этой функции может возникать при неявном задании частоты МК. Например, в L-серии при выходе из стоп-режимов МК может запускаться на иной частоте, чем при нормальном старте по POR.

Re: Stm32 с чего начать изучение...

Пт апр 22, 2022 20:52:36

делать функцию расчёта частоты работы МК.

Она уже есть! Найдите поиском ф-цию SystemCoreClockUpdate. Она входит в стандартную поставку и генерируется вместе с созданием проекта.
Эта функция обновляет глобальную переменную SystemCoreClock, которая может использоваться в выражениях для задания частотозависимых интервалов. Например при настройке таймера.
Необходимость в этой функции может возникать при неявном задании частоты МК. Например, в L-серии при выходе из стоп-режимов МК может запускаться на иной частоте, чем при нормальном старте по POR.
Большое спаси за наводку! Действительно, там, в SystemCoreClockUpdate происходит нужный мне расчёт. Но... Если я ссылаюсь на эту переменную (sysclockfreq) в основной программе - компилятор ругается на необьявленность (делаю всё в CubeIDE). Так же и с другими переменными из этой функции. Ещё есть функция uint32_t HAL_RCC_GetHCLKFreq(void). С ней та же беда. Что-то не пойму, как заставить выполняться эти функции... Файлы прикреплены к проекту...


VladislavS писал(а):Все делители в конце концов ложатся в регистры RCC. Оттуда их можно читать. Только пустое это. Зачем вычислять то что вы сами же и задаёта?
Всё в виде научного эксперимента :) В рамках изучения STM32 =)

Re: Stm32 с чего начать изучение...

Пт апр 22, 2022 21:12:27

Эта переменная объявляется как extern в одноименном заголовочном файле (system_stm32.... .h) и по идее, этот файл должен быть подключен при геренации проекта в CubeIDE.
В любом случае, вы можете объявить переменную вручную через extern в нужном месте:
extern uint32_t SystemCoreClock;

Re: Stm32 с чего начать изучение...

Пт апр 22, 2022 21:18:28

Эта переменная объявляется как extern в одноименном заголовочном файле (system_stm32.... .h) и по идее, этот файл должен быть подключен при геренации проекта в CubeIDE.
В любом случае, вы можете объявить переменную вручную через extern в нужном месте:
extern uint32_t SystemCoreClock;

Большое спасибо за советы, друзья! Что-то получилось) Ещё не понял что) Странные данные на экран вывел (31232 зайцев). Ошибку нашёл, двигаюсь дальше! :beer:

UPD: всё, вывел правильно :) 168 МГц =)

Re: Stm32 с чего начать изучение...

Вс май 01, 2022 21:45:21

Всем привет!
4 дня впервые потратил на приобщение к F030F4P6, из-за 12-битного ADC.
Проект собираю в STM32CubeIDE 1.9.0. Исходники моего говнотворения прилагаю.
Собственно, мой вопрос. В avr-gcc я мог легко оформить кусок кода в виде:
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
...
}
а здесь (gcc-arm-none-eabi) не понятно, по хидерам искал, ничего дельного не нашел.
Как включить кусок кода в атомик-блок?
Или, какие-то другие механизмы задействуются?
И, буду рад к критическим коментариям к приложенной писанине.

main.h
Спойлер
Код:
#pragma once

#define DEBUG_USART1   1
#define SOME_FUNC      1
#define LED_FLASH      1

extern volatile uint32_t uwTick;

#define ChDataBits   (8u)
#define ChDataSize   (1u << ChDataBits)

typedef struct {
   uint16_t ch0;
   uint16_t ch1;
} ChData_TypeDef;

extern volatile ChData_TypeDef ChData[ChDataSize];
extern volatile uint16_t adcRawCh0, adcRawCh1;

void initRCC(void);
void initGPIO(void);
void initADC1(void);

void calADC1(void);
void stopADC1(void);
void startADC1(void* pData, uint16_t num, uint32_t ch, uint8_t stime);

#ifdef SOME_FUNC
void delayMs(uint32_t delay);
uint16_t scmADC1(uint32_t ch);
#endif

#ifdef DEBUG_USART1
extern char aText[64];
void initUSART1(void);
void postsz(char* pSz);
void sendsz(char* pSz);
void sendc(char c);
#endif

main.c
Спойлер
Код:
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <inttypes.h>
#include "stm32f0xx.h"
#include "main.h"

volatile ChData_TypeDef ChData[ChDataSize];
volatile uint16_t adcRawCh0 = 0, adcRawCh1 = 0;

// DMA1 Channel 2 and Channel 3 interrupt handler
void DMA1_Channel2_3_IRQHandler(void)
{
   // A Transfer Complete or Transfer Error flag
   if(READ_BIT(DMA1->ISR, DMA_ISR_TCIF2 | DMA_ISR_TEIF2) != RESET) {
      // Disable DMA1 Channel2
      CLEAR_BIT(DMA1_Channel2->CCR, DMA_CCR_EN);
      // Channel2 clear interrupt flags
      SET_BIT(DMA1->IFCR, DMA_IFCR_CGIF2 | DMA_IFCR_CTCIF2 | DMA_IFCR_CHTIF2 | DMA_IFCR_CTEIF2);
      // average calc
      uint32_t sch0 = 0, sch1 = 0;
      ChData_TypeDef* pch = (ChData_TypeDef*)ChData;
      for(uint16_t i = 0; i < (sizeof(ChData)/(sizeof(ChData[0]))); i++, pch++) {
         sch0 += pch->ch0;
         sch1 += pch->ch1;
      }
      sch0 += (sizeof(ChData)/(sizeof(ChData[0]))) >> 1;
      sch1 += (sizeof(ChData)/(sizeof(ChData[0]))) >> 1;
      adcRawCh0 = sch0 >> ChDataBits;
      adcRawCh1 = sch1 >> ChDataBits;
   }
}

int main(void)
{
   initRCC();
   initGPIO();
#ifdef DEBUG_USART1
   initUSART1();
#endif
   initADC1();
   memset((void*)ChData, 0, sizeof(ChData));

#ifdef LED_FLASH
   SET_BIT(GPIOB->BSRR, GPIO_BSRR_BS_1);
#endif
#ifdef DEBUG_USART1
   postsz("\r\nStart!\r\n\r\n");
#endif

   uint32_t uwAdcMs = uwTick;
   uint32_t uwCalcMs = uwTick;
#ifdef LED_FLASH
   uint32_t uwLedMs = uwTick;
#endif
   while(1) {
      if(uwTick - uwAdcMs >= 100u) { // every 100 msec
         uwAdcMs = uwTick;
         startADC1((void*)ChData,
               (sizeof(ChData)/(sizeof(ChData[0])) << 1),
               ADC_CHSELR_CHSEL1 | ADC_CHSELR_CHSEL0,
               ADC_SMPR_SMP_2 | ADC_SMPR_SMP_1);   // tCONV = 6 usec
      }
      if(uwTick - uwCalcMs >= 500u) { // every 500 msec
         uwCalcMs = uwTick;
         sprintf(aText, "%u\t%u\r\n", adcRawCh0, adcRawCh1);
         postsz(aText);
      }
#ifdef LED_FLASH
      if(uwTick - uwLedMs >= 500u) { // every 500 msec
         uwLedMs = uwTick;
         SET_BIT(GPIOB->BSRR, READ_BIT(GPIOB->IDR, GPIO_IDR_1) ? GPIO_BSRR_BR_1 : GPIO_BSRR_BS_1);
      }
#endif
   }
}

// GPIO initialization
void initGPIO(void)
{
   // I/O port A, B, F clock enable
   SET_BIT(RCC->AHBENR, RCC_AHBENR_GPIOAEN | RCC_AHBENR_GPIOBEN | RCC_AHBENR_GPIOFEN);
   // ADC1: PORTA0 (NTC0), PORTA1 (NTC1) Analog mode
   SET_BIT(GPIOA->MODER, GPIO_MODER_MODER0 | GPIO_MODER_MODER1);

#ifdef LED_FLASH
   // PORTB1: General purpose output mode (LED)
   MODIFY_REG(GPIOB->MODER, GPIO_MODER_MODER1, GPIO_MODER_MODER1_0);
   // PORTB1: push-pull
   CLEAR_BIT(GPIOB->OTYPER, GPIO_OTYPER_OT_1);
   // PORTB1: 2 MHz
   CLEAR_BIT(GPIOB->OSPEEDR, GPIO_OSPEEDR_OSPEEDR1);
   // PORTB1: No pull-up or pull-down
   CLEAR_BIT(GPIOB->PUPDR, GPIO_PUPDR_PUPDR1);
#endif

#ifdef DEBUG_USART1
   // USART1: PORTA9 (Tx), PORTA10 (Rx): Alternate function mode
   MODIFY_REG(GPIOA->MODER, GPIO_MODER_MODER9 | GPIO_MODER_MODER10, GPIO_MODER_MODER9_1 | GPIO_MODER_MODER10_1);
   // PORTA9 (Tx), PORTA10 (Rx): Output push-pull
   CLEAR_BIT(GPIOA->OTYPER, GPIO_OTYPER_OT_9 | GPIO_OTYPER_OT_10);
   // PORTA9 (Tx), PORTA10 (Rx): 50 MHz
   SET_BIT(GPIOA->OSPEEDR, GPIO_OSPEEDR_OSPEEDR9_0 | GPIO_OSPEEDR_OSPEEDR9_1 | GPIO_OSPEEDR_OSPEEDR10_0 | GPIO_OSPEEDR_OSPEEDR10_1);
   // PORTA9 (Tx): No pull-up or pull-down, PORTA10 (Rx): Pull-up
   MODIFY_REG(GPIOA->PUPDR, GPIO_PUPDR_PUPDR9 | GPIO_PUPDR_PUPDR10, GPIO_PUPDR_PUPDR10_0);
   // PORTA9 (Tx), PORTA10 (Rx): Alternate function AF1
   MODIFY_REG(GPIOA->AFR[1], GPIO_AFRH_AFSEL9 | GPIO_AFRH_AFSEL10, (1UL << GPIO_AFRH_AFSEL9_Pos) | (1UL << GPIO_AFRH_AFSEL10_Pos));
#endif
}

// ADC stop
void stopADC1(void)
{
   // ADC group regular conversion stop
   if(READ_BIT(ADC1->CR, ADC_CR_ADSTART) != RESET) {
      SET_BIT(ADC1->CR, ADC_CR_ADSTP);
      // wait for ADC group regular conversion stop
      while(READ_BIT(ADC1->CR, ADC_CR_ADSTP) != RESET);
   }
}

// ADC start
void startADC1(void* pData, uint16_t num, uint32_t ch, uint8_t stime)
{
   // ADC stop
   stopADC1();
   // Sampling time selection, Fadc = 14 MHz
   //   SMP      Sampling      tCONV,
   //         time,ADCcycles   usec
   //   000      1,5            1,00
   //   001      7,5            1,43
   //   010      13,5         1,86
   //   011      28,5         2,93
   //   100      41,5         3,86
   //   101      55,5         4,86
   //   110      71,5         6,00
   //   111      239,5         18,00
   MODIFY_REG(ADC1->SMPR, ADC_SMPR_SMP, stime);
   // ADC channel selection
   MODIFY_REG(ADC1->CHSELR, ADC_CHSELR_CHSEL, ch);
   // Analog watchdog disabled, ADC group regular sequencer discontinuous mode disabled,
   // ADC low power auto power off disabled, Wait conversion mode off,
   // DR register is preserved with the old data when an overrun is detected,
   // Hardware trigger detection disabled, Right alignment, Data resolution 12 bits,
   // Scan sequence direction Upward, DMA one shot mode selected,
   // Continuous conversion mode enabled, DMA enabled
   MODIFY_REG(ADC1->CFGR1, ADC_CFGR1_AWD1EN | ADC_CFGR1_DISCEN | ADC_CFGR1_AUTOFF | ADC_CFGR1_WAIT |
      ADC_CFGR1_OVRMOD | ADC_CFGR1_EXTEN | ADC_CFGR1_ALIGN | ADC_CFGR1_RES | ADC_CFGR1_SCANDIR | ADC_CFGR1_DMACFG,
      ADC_CFGR1_CONT | ADC_CFGR1_DMAEN);

   // DMA
   // wait DMA1 Channel2 Transfer Complete flag
   if(READ_BIT(DMA1_Channel2->CCR, DMA_CCR_EN) != RESET)
      // wait for Transfer Complete or Transfer Error flag
      while(READ_BIT(DMA1->ISR, DMA_ISR_TCIF2 | DMA_ISR_TEIF2) == RESET);
   // Disable DMA1 Channel2
   CLEAR_BIT(DMA1_Channel2->CCR, DMA_CCR_EN);
   // ADC DMA remap to DMA1 Chanel2
   SET_BIT(SYSCFG->CFGR1, SYSCFG_CFGR1_ADC_DMA_RMP);
   // Configure the peripheral address register
   WRITE_REG(DMA1_Channel2->CPAR, (uint32_t)&(ADC1->DR));
   // Configure the memory address
   WRITE_REG(DMA1_Channel2->CMAR, (uint32_t)pData);
   // Configure the number of DMA tranfer to be performs on channel
   MODIFY_REG(DMA1_Channel2->CNDTR, 0xffffu, num);
   // Channel priority level 01 Medium, Peripheral & Memory size 01 16-bits,
   // Memory increment mode 1 enabled, Data transfer direction 0 Read from peripheral
   // Circular mode disabled, Transfer complete interrupt enabled
   MODIFY_REG(DMA1_Channel2->CCR, DMA_CCR_MEM2MEM | DMA_CCR_PL | DMA_CCR_MSIZE | DMA_CCR_PSIZE |
      DMA_CCR_PINC | DMA_CCR_CIRC | DMA_CCR_DIR | DMA_CCR_TEIE | DMA_CCR_HTIE | DMA_CCR_EN,
      DMA_CCR_PL_0 | DMA_CCR_MSIZE_0 | DMA_CCR_PSIZE_0 | DMA_CCR_MINC | DMA_CCR_TCIE);

   // ADC group regular conversion start
   SET_BIT(ADC1->CR, ADC_CR_ADSTART);
   // Enable DMA1 Channel2
   SET_BIT(DMA1_Channel2->CCR, DMA_CCR_EN);

   // DMA1 Channel2 (ADC) and Channel3 interrupt enable
   NVIC_EnableIRQ(DMA1_Channel2_3_IRQn);
   NVIC_SetPriority(DMA1_Channel2_3_IRQn, 2);
}

// ADC calibration
void calADC1(void)
{
   // ADC disable
   if(READ_BIT(ADC1->CR, ADC_CR_ADEN) != RESET) {
      // ADC stop
      stopADC1();
      // ADC disable
      SET_BIT(ADC1->CR, ADC_CR_ADDIS);
      // wait for ADC1 disable
      while(READ_BIT(ADC1->CR, ADC_CR_ADEN) != RESET);
   }

   // ADC DMA transfer disable
   CLEAR_BIT(ADC1->CFGR1, ADC_CFGR1_DMAEN | ADC_CFGR1_DMACFG);
   // ADC calibration
   SET_BIT(ADC1->CR, ADC_CR_ADCAL);
   // Wait until ADCAL=0
   while(READ_BIT(ADC1->CR, ADC_CR_ADCAL) != RESET);

   // ADC Enable
   // Clear the ADRDY bit
   if(READ_BIT(ADC1->ISR, ADC_ISR_ADRDY) != RESET)
      SET_BIT(ADC1->ISR, ADC_ISR_ADRDY);
   // ADC enable
   SET_BIT(ADC1->CR, ADC_CR_ADEN);
   // wait for ADC ready flag
   while(READ_BIT(ADC1->ISR, ADC_ISR_ADRDY) == RESET);
}

// ADC initialization
void initADC1(void)
{
   // HSI14 clock request from ADC disable
   SET_BIT(RCC->CR2, RCC_CR2_HSI14DIS);
   // Internal High Speed 14MHz clock enable
   SET_BIT(RCC->CR2, RCC_CR2_HSI14ON);
   // wait for Internal High Speed 14MHz clock ready
   while(READ_BIT(RCC->CR2, RCC_CR2_HSI14RDY) == RESET);
   // Internal High Speed 14MHz clock enable
   CLEAR_BIT(RCC->CR2, RCC_CR2_HSI14DIS);
   // ADCCLK (Asynchronous clock mode), generated at product level (refer to RCC section)
   CLEAR_BIT(ADC1->CFGR2, RCC_CFGR2_PREDIV);
   // ADC1 clock enable
   SET_BIT(RCC->APB2ENR, RCC_APB2ENR_ADCEN);
   // ADC calibration
   calADC1();
}

volatile uint32_t uwTick = 0;

// SysTick interrupt handler
void SysTick_Handler(void)
{
   uwTick++;
}

// RCC initialization
void initRCC(void)
{
   // SYSCFG and comparator clock enable
   SET_BIT(RCC->APB2ENR, RCC_APB2ENR_SYSCFGCOMPEN);
   // Flash Latency: One wait state, if 24 MHz < SYSCLK ≤ 48 MHz
   SET_BIT(FLASH->ACR, FLASH_ACR_LATENCY);

   // Enable the Internal High Speed oscillator (HSI)
   SET_BIT(RCC->CR, RCC_CR_HSION);
   while(READ_BIT(RCC->CR, RCC_CR_HSIRDY) == RESET);

   // Disable the main PLL
   CLEAR_BIT(RCC->CR, RCC_CR_PLLON);
   while(READ_BIT(RCC->CR, RCC_CR_PLLRDY) != RESET);

   // PLL HSI /2 x12
   MODIFY_REG(RCC->CFGR, RCC_CFGR_PLLSRC | RCC_CFGR_PLLMUL, RCC_CFGR_PLLSRC_HSI_DIV2|RCC_CFGR_PLLMUL12);
   MODIFY_REG(RCC->CFGR2, RCC_CFGR2_PREDIV, RCC_CFGR2_PREDIV_DIV1);

   // Enable the PLL
   SET_BIT(RCC->CR, RCC_CR_PLLON);
   while(READ_BIT(RCC->CR, RCC_CR_PLLRDY) == RESET);

   // HCLK and PCLK: no prescaler, System clock: PLL 48 MHz
   MODIFY_REG(RCC->CFGR, RCC_CFGR_HPRE | RCC_CFGR_PPRE | RCC_CFGR_SW, RCC_CFGR_HPRE_DIV1 | RCC_CFGR_PPRE_DIV1 | RCC_CFGR_SW_PLL);
   // PLL used as system clock
   while(READ_BIT(RCC->CFGR, RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL);

   // set system variable SystemCoreClock to current clock value
   SystemCoreClockUpdate();
   // set SysTick timer to 1 ms delay
   SysTick_Config(SystemCoreClock / 1000);

   // DMA1 clock enable
   SET_BIT(RCC->AHBENR, RCC_AHBENR_DMAEN);
}

#ifdef SOME_FUNC

// set delay in miliseconds using sysTick timer
void delayMs(uint32_t delay)
{
   uint32_t uwT0 = uwTick;
   while(uwTick - uwT0 < delay);
}

uint16_t scmADC1(uint32_t ch)
{
   // ADC stop
   stopADC1();
   // Sampling time selection
   MODIFY_REG(ADC1->SMPR, ADC_SMPR_SMP, ADC_SMPR_SMP_2);
   // Analog watchdog disabled, ADC group regular sequencer discontinuous mode disabled,
   // ADC low power auto power off disabled, Wait conversion mode off,
   // Continuous conversion mode disabled, DR register is preserved with the old data when an overrun is detected,
   // Hardware trigger detection disabled, Right alignment, Data resolution 12 bits,
   // Scan sequence direction Upward, DMA one shot mode selected, DMA disabled
   CLEAR_BIT(ADC1->CFGR1, ADC_CFGR1_AWD1EN | ADC_CFGR1_DISCEN | ADC_CFGR1_AUTOFF | ADC_CFGR1_WAIT |
      ADC_CFGR1_CONT | ADC_CFGR1_OVRMOD | ADC_CFGR1_EXTEN | ADC_CFGR1_ALIGN | ADC_CFGR1_RES |
      ADC_CFGR1_SCANDIR | ADC_CFGR1_DMACFG | ADC_CFGR1_DMAEN);
   // ADC channel selection
   MODIFY_REG(ADC1->CHSELR, ADC_CHSELR_CHSEL, ch);
   // ADC group regular conversion start
   SET_BIT(ADC1->CR, ADC_CR_ADSTART);
   // ADC group regular end of unitary conversion flag
   while(READ_BIT(ADC1->ISR, ADC_ISR_EOC) == RESET);
   // ADC data register
   return (uint16_t)(READ_REG(ADC1->DR) & 0xffffu);
}

#endif

#ifdef DEBUG_USART1

char aText[64];

// USART initialization
void initUSART1(void)
{
   // System clock (SYSCLK) selected as USART1 clock
   MODIFY_REG(RCC->CFGR3, RCC_CFGR3_USART1SW, RCC_CFGR3_USART1SW_SYSCLK);
   // USART1 clock enable
   SET_BIT(RCC->APB2ENR, RCC_APB2ENR_USART1EN);

   // USART1: Baud rate 115200 for standard USART (oversampling by 16, OVER8 = 0)
   MODIFY_REG(USART1->BRR, 0xffffu, 417u);
   // USART1: DMA Enable Transmitter
   SET_BIT(USART1->CR3, USART_CR3_DMAT);
   // USART1: 1 stop bit, CK pin disabled,
   // USART1->CR2 = 0;
   // USART1: 1 Start bit, 8 data bits, Parity control disabled, Oversampling by 16,
   // Transmitter Enable, Receiver Enable, USART1 Enable | USART_CR1_RE
   SET_BIT(USART1->CR1, USART_CR1_TE | USART_CR1_UE);

}

void postsz(char* pSz)
{
   // wait DMA1 Channel4 Transfer Complete flag
   if(READ_BIT(DMA1_Channel4->CCR, DMA_CCR_EN))
      // wait for Transfer Complete or Transfer Error flag
      while(READ_BIT(DMA1->ISR, DMA_ISR_TCIF4 | DMA_ISR_TEIF4) == RESET);
   // Disable DMA1 Channel4
   CLEAR_BIT(DMA1_Channel4->CCR, DMA_CCR_EN);
   // Remap (USART1_TX DMA request mapped on DMA channel 4)
   SET_BIT(SYSCFG->CFGR1, SYSCFG_CFGR1_USART1TX_DMA_RMP);
   // Configure the peripheral address register
   WRITE_REG(DMA1_Channel4->CPAR, (uint32_t)&(USART1->TDR));
   // Configure the memory address
   WRITE_REG(DMA1_Channel4->CMAR, (uint32_t)pSz);
   // Configure the number of DMA tranfer to be performs on channel
   WRITE_REG(DMA1_Channel4->CNDTR, strlen(pSz));
   // Channel priority level 00 Low, Peripheral & Memory size 00 8-bits,
   // Memory increment mode 1 enabled, Data transfer direction 1: Read from memory
   MODIFY_REG(DMA1_Channel4->CCR, DMA_CCR_MEM2MEM | DMA_CCR_PL | DMA_CCR_MSIZE | DMA_CCR_PSIZE |
      DMA_CCR_PINC | DMA_CCR_CIRC | DMA_CCR_TEIE | DMA_CCR_HTIE | DMA_CCR_TCIE | DMA_CCR_EN,
      DMA_CCR_MINC | DMA_CCR_DIR);
   // Enable DMA1 Channel4
   SET_BIT(DMA1_Channel4->CCR, DMA_CCR_EN);
}

void sendsz(char* pSz)
{
   if(pSz)
      while(*pSz)
         sendc(*pSz++);
}

void sendc(char c)
{
   // wait
   if(READ_BIT(DMA1_Channel4->CCR, DMA_CCR_EN))
      // wait DMA1 Channel4 Transfer Complete flag
      while(READ_BIT(DMA1->ISR, DMA_ISR_TCIF4 | DMA_ISR_TEIF4) == RESET);
   else
      // Wait Transmit Data Register Empty
      while(READ_BIT(USART1->ISR, USART_ISR_TXE) == RESET);
   USART1->TDR = c;
}

#endif
Вложения
STM32F030 clean USART DMA ADC.rar
(81.56 KiB) Скачиваний: 63

Re: Stm32 с чего начать изучение...

Пн май 02, 2022 10:37:12

Как включить кусок кода в атомик-блок?
Вариантов много. Самое простое
Код:
  uint32_t tmp = __get_PRIMASK();
  __disable_irq();
  // код
  __set_PRIMASK(tmp);

Re: Stm32 с чего начать изучение...

Пн май 02, 2022 10:55:14

Вот это портянка... Вы лучше на словах скажите, куда хотите впендюрить атомарность и почему, соппсна, оная вам нужна для АЦП?
Атомарность - она для чего нужна: если в обработчике прерывания вы обращаетесь к тому же ресурсу, что и и в общем коде. Или при работе с RTOS. Но RTOS предоставляет свои алгоритмы защиты. Без RTOS можно временно отключить вектор прерывания (через функции NVIC), в котором происходит параллельное действие. Или временно полностью запертить прерывания.
Ответить