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

Кто любит RISC в жизни, заходим, не стесняемся.
linkov1959
Держит паяльник хвостом
Сообщения: 923
Зарегистрирован: Пн сен 10, 2018 19:16:28

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

Сообщение linkov1959 »

ПростоНуб, ассемблер - это язык высокого уровня, "специалист" я программировал тумблерами, вводя двоичный код.:)
Реклама
Аватара пользователя
ПростоНуб
Собутыльник Кота
Сообщения: 2723
Зарегистрирован: Пт сен 07, 2018 20:20:02
Откуда: деревня в Тульской губернии

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

Сообщение ПростоНуб »

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

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

Сообщение ARV »

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

Мой уютный бложик... заходите!
Аватара пользователя
VladislavS
Собутыльник Кота
Сообщения: 2562
Зарегистрирован: Вт май 01, 2018 19:44:47

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

Сообщение VladislavS »

Мне вот ночью приснилось, что при выполнении кода из 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
Реклама
Эиком - электронные компоненты и радиодетали
linkov1959
Держит паяльник хвостом
Сообщения: 923
Зарегистрирован: Пн сен 10, 2018 19:16:28

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

Сообщение linkov1959 »

ПростоНуб, А ещё, извращенцы стирали РФки сваркой!
Реклама
Аватара пользователя
ПростоНуб
Собутыльник Кота
Сообщения: 2723
Зарегистрирован: Пт сен 07, 2018 20:20:02
Откуда: деревня в Тульской губернии

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

Сообщение ПростоНуб »

linkov1959, тогда уж солнышком. Но некоторые пытались это делать через оконное стекло, забыв, что оно ультрафиолет не пропускает )))
Но это реально изврат, так как люминисцентные УФ лампы тогда были вполне доступны в продаже. Великоваты, конечно, так как предназначались для загара или в медицинских целях. Но вполне пригодны для стирания РФ-ок.
Реклама
Аватара пользователя
Мурик
Друг Кота
Сообщения: 3383
Зарегистрирован: Пн окт 11, 2010 19:00:08

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

Сообщение Мурик »

ПростоНуб писал(а):тогда уж солнышком.
Пробовал. Это долго. Понадобилось около 2-ух месяцев нахождения на солнце.
Лучше уж
linkov1959 писал(а):сваркой
:))) :)))
Аватара пользователя
ПростоНуб
Собутыльник Кота
Сообщения: 2723
Зарегистрирован: Пт сен 07, 2018 20:20:02
Откуда: деревня в Тульской губернии

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

Сообщение ПростоНуб »

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

P.S. На Роман-коше стирать не пробовал. Подозреваю, что на высоте в полтора километра за несколько часов бы все стерлись )
Dimon456
Мудрый кот
Сообщения: 1849
Зарегистрирован: Вс дек 25, 2016 08:34:54

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

Сообщение Dimon456 »

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 толком ни чего не работает.
Аватара пользователя
VladislavS
Собутыльник Кота
Сообщения: 2562
Зарегистрирован: Вт май 01, 2018 19:44:47

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

Сообщение VladislavS »

[uquote="Dimon456",url="/forum/viewtopic.php?p=4168928#p4168928"]а я то думал, но по чему из ram толком ни чего не работает.[/uquote]Вывод неверный. Копирование данных самих в себя только время лишнее занимает и ничего в работе прошивки не меняет.
Professor Chaos
Открыл глаза
Сообщения: 41
Зарегистрирован: Вс мар 21, 2021 11:06:04

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

Сообщение Professor Chaos »

Dimon456 писал(а):И где само копирование? Самому ручками прописывать?
Видимо, внутри __PROGRAM_START(). Это ведь Enter PreMain (C library entry point). Там создаются и инициализируются начальными значениями глобальные и локальные статические данные в RAM-памяти.
Аватара пользователя
DataLife
Вымогатель припоя
Сообщения: 601
Зарегистрирован: Пт фев 13, 2009 20:58:13
Откуда: Донецк

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

Сообщение DataLife »

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

Заранее спасибо и простите мою неграмотность :)
Только те, кто предпринимают абсурдные попытки, смогут достичь невозможного.
Аватара пользователя
VladislavS
Собутыльник Кота
Сообщения: 2562
Зарегистрирован: Вт май 01, 2018 19:44:47

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

Сообщение VladislavS »

Все делители в конце концов ложатся в регистры RCC. Оттуда их можно читать. Только пустое это. Зачем вычислять то что вы сами же и задаёта?
Аватара пользователя
НовыйДень
Потрогал лапой паяльник
Сообщения: 362
Зарегистрирован: Вс апр 03, 2022 07:01:29

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

Сообщение НовыйДень »

делать функцию расчёта частоты работы МК.
Она уже есть! Найдите поиском ф-цию SystemCoreClockUpdate. Она входит в стандартную поставку и генерируется вместе с созданием проекта.
Эта функция обновляет глобальную переменную SystemCoreClock, которая может использоваться в выражениях для задания частотозависимых интервалов. Например при настройке таймера.
Необходимость в этой функции может возникать при неявном задании частоты МК. Например, в L-серии при выходе из стоп-режимов МК может запускаться на иной частоте, чем при нормальном старте по POR.
Аватара пользователя
DataLife
Вымогатель припоя
Сообщения: 601
Зарегистрирован: Пт фев 13, 2009 20:58:13
Откуда: Донецк

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

Сообщение DataLife »

[uquote="НовыйДень",url="/forum/viewtopic.php?p=4220054#p4220054"]
делать функцию расчёта частоты работы МК.
Она уже есть! Найдите поиском ф-цию SystemCoreClockUpdate. Она входит в стандартную поставку и генерируется вместе с созданием проекта.
Эта функция обновляет глобальную переменную SystemCoreClock, которая может использоваться в выражениях для задания частотозависимых интервалов. Например при настройке таймера.
Необходимость в этой функции может возникать при неявном задании частоты МК. Например, в L-серии при выходе из стоп-режимов МК может запускаться на иной частоте, чем при нормальном старте по POR.[/uquote]Большое спаси за наводку! Действительно, там, в SystemCoreClockUpdate происходит нужный мне расчёт. Но... Если я ссылаюсь на эту переменную (sysclockfreq) в основной программе - компилятор ругается на необьявленность (делаю всё в CubeIDE). Так же и с другими переменными из этой функции. Ещё есть функция uint32_t HAL_RCC_GetHCLKFreq(void). С ней та же беда. Что-то не пойму, как заставить выполняться эти функции... Файлы прикреплены к проекту...

VladislavS писал(а):Все делители в конце концов ложатся в регистры RCC. Оттуда их можно читать. Только пустое это. Зачем вычислять то что вы сами же и задаёта?
Всё в виде научного эксперимента :) В рамках изучения STM32 =)
Только те, кто предпринимают абсурдные попытки, смогут достичь невозможного.
Аватара пользователя
НовыйДень
Потрогал лапой паяльник
Сообщения: 362
Зарегистрирован: Вс апр 03, 2022 07:01:29

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

Сообщение НовыйДень »

Эта переменная объявляется как extern в одноименном заголовочном файле (system_stm32.... .h) и по идее, этот файл должен быть подключен при геренации проекта в CubeIDE.
В любом случае, вы можете объявить переменную вручную через extern в нужном месте:
extern uint32_t SystemCoreClock;
Аватара пользователя
DataLife
Вымогатель припоя
Сообщения: 601
Зарегистрирован: Пт фев 13, 2009 20:58:13
Откуда: Донецк

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

Сообщение DataLife »

[uquote="НовыйДень",url="/forum/viewtopic.php?p=4220096#p4220096"]Эта переменная объявляется как extern в одноименном заголовочном файле (system_stm32.... .h) и по идее, этот файл должен быть подключен при геренации проекта в CubeIDE.
В любом случае, вы можете объявить переменную вручную через extern в нужном месте:
extern uint32_t SystemCoreClock;[/uquote]
Большое спасибо за советы, друзья! Что-то получилось) Ещё не понял что) Странные данные на экран вывел (31232 зайцев). Ошибку нашёл, двигаюсь дальше! :beer:

UPD: всё, вывел правильно :) 168 МГц =)
Только те, кто предпринимают абсурдные попытки, смогут достичь невозможного.
Аватара пользователя
Карбофос
Опытный кот
Сообщения: 760
Зарегистрирован: Сб окт 22, 2016 17:33:32
Откуда: кг

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

Сообщение Карбофос »

Всем привет!
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 КБ) 104 скачивания
Аватара пользователя
VladislavS
Собутыльник Кота
Сообщения: 2562
Зарегистрирован: Вт май 01, 2018 19:44:47

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

Сообщение VladislavS »

[uquote="Карбофос",url="/forum/viewtopic.php?p=4225283#p4225283"]Как включить кусок кода в атомик-блок?[/uquote]Вариантов много. Самое простое

Код: Выделить всё

  uint32_t tmp = __get_PRIMASK();
  __disable_irq();
  // код
  __set_PRIMASK(tmp);
Аватара пользователя
НовыйДень
Потрогал лапой паяльник
Сообщения: 362
Зарегистрирован: Вс апр 03, 2022 07:01:29

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

Сообщение НовыйДень »

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

Вернуться в «ARM»