Всякие фиксы модели и заготовки для АЦП

И почему то все равно MATLAB намертво блокирует mingw64.... Приходится перезапускать матлаб для перекомпиляции
This commit is contained in:
2025-11-09 21:04:52 +03:00
parent be84043f18
commit 79ff2667c4
74 changed files with 2371 additions and 609 deletions

View File

@@ -1,4 +1,5 @@
#include "stm32_matlab_adc.h"
#include "stm32_matlab_dma.h"
#include <string.h>
@@ -22,19 +23,26 @@ void ADC_Simulation(ADC_TypeDef* ADCx, struct ADC_Sim* ADCS)
{
if (!(ADCx->CR2 & ADC_CR2_ADON)) return;
// Start conversion on SWSTART
// ПЕРВОЕ: Проверка внешнего триггера (для режима по триггеру)
if (!(ADCx->CR2 & ADC_CR2_CONT)) { // Только если не continuous mode
ADC_Check_External_Trigger(ADCx, ADCS);
}
// ВТОРОЕ: Software trigger
if (ADCx->CR2 & ADC_CR2_SWSTART) {
ADC_Start_Conversion(ADCx, ADCS);
ADCx->CR2 &= ~ADC_CR2_SWSTART;
}
// Handle ongoing conversion - ïðîâåðÿåì ïî ôëàãó ñîñòîÿíèÿ
// ТРЕТЬЕ: Обработка текущего преобразования
if (ADCS->conversion_time_elapsed >= 0) {
ADCS->conversion_time_elapsed += ADCS->simulation_step;
double total_time = ADC_Get_Total_Conversion_Time(ADCx, ADCS);
// ИСПОЛЬЗУЕМ ОБЩЕЕ ВРЕМЯ ДЛЯ ВСЕЙ ПОСЛЕДОВАТЕЛЬНОСТИ
double total_time = ADC_Get_Total_Sequence_Time(ADCx, ADCS);
if (ADCS->conversion_time_elapsed >= total_time) {
ADC_Complete_Conversion(ADCx, ADCS);
ADC_Complete_Conversion(ADCx, ADCS); // Обрабатываем ВСЕ каналы
// Continuous mode auto-restart
if (ADCx->CR2 & ADC_CR2_CONT) {
@@ -42,19 +50,18 @@ void ADC_Simulation(ADC_TypeDef* ADCx, struct ADC_Sim* ADCS)
}
}
}
}
void ADC_Start_Conversion(ADC_TypeDef* ADCx, struct ADC_Sim* ADCS)
{
// Îïðåäåëÿåì êàíàë äëÿ êîíâåðñèè
// Определяем канал для конверсии
if (ADCx->CR1 & ADC_CR1_SCAN) {
// Ðåæèì ñêàíèðîâàíèÿ
// Режим сканирования
ADCS->current_rank = 0;
ADCS->current_channel = ADC_Get_Sequence_Channel(ADCx, 0);
}
else {
// Îäèíî÷íûé êàíàë
// Одиночный канал
ADCS->current_channel = ADC_Get_Sequence_Channel(ADCx, 0);
}
@@ -63,81 +70,210 @@ void ADC_Start_Conversion(ADC_TypeDef* ADCx, struct ADC_Sim* ADCS)
void ADC_Complete_Conversion(ADC_TypeDef* ADCx, struct ADC_Sim* ADCS)
{
// Êîíâåðòèðóåì àíàëîãîâîå çíà÷åíèå â öèôðîâîå
double analog_val = 0;
if (ADCS->channel_connected[ADCS->current_channel]) {
analog_val = ADCS->channel_values[ADCS->current_channel];
uint32_t seq_len = ADC_Get_Sequence_Length(ADCx);
// Обрабатываем ВСЕ каналы последовательности за один вызов
for (uint32_t rank = 0; rank < seq_len; rank++) {
uint32_t channel = ADC_Get_Sequence_Channel(ADCx, rank);
// 1. Конвертируем один канал
double analog_val = 0;
if (ADCS->channel_connected[channel]) {
analog_val = ADCS->channel_values[channel];
}
if (analog_val < 0) analog_val = 0;
if (analog_val > 3.3) analog_val = 3.3;
// Вычисляем значение АЦП
ADCS->last_conversion_value = (uint16_t)((analog_val / 3.3) * 4095.0);
// Добавляем шум
int32_t noisy_value = (int32_t)ADCS->last_conversion_value + (rand() % (2 * ADC_NOISE_LSB + 1)) - ADC_NOISE_LSB;
if (noisy_value < 0) noisy_value = 0;
if (noisy_value > 4095) noisy_value = 4095;
ADCS->last_conversion_value = (uint16_t)noisy_value;
// 2. Записываем в DR
ADCx->DR = ADCS->last_conversion_value;
// 3. Устанавливаем флаг EOC
ADCx->SR |= ADC_SR_EOC;
// 4. СРАЗУ вызываем DMA для этой конверсии
if (ADCx->CR2 & ADC_CR2_DMA) {
if (ADCx == ADC3) {
DMA_Sim_Transfer(DMA2, 0); // Выполняем одну передачу
}
else if (ADCx == ADC1) {
DMA_Sim_Transfer(DMA2, 4); // Для ADC1
}
}
}
if (analog_val < 0)
analog_val = 0;
if (analog_val > 3.3)
analog_val = 3.3;
// Ñíà÷àëà âû÷èñëÿåì çíà÷åíèå ÀÖÏ
ADCS->last_conversion_value = (uint16_t)((analog_val / 3.3) * 4095.0);
// Ïîòîì äîáàâëÿåì øóì â LSB
int32_t noisy_value = (int32_t)ADCS->last_conversion_value + (rand() % (2 * ADC_NOISE_LSB + 1)) - ADC_NOISE_LSB;
// Ñàòóðàöèÿ öèôðîâîãî çíà÷åíèÿ
if (noisy_value < 0) noisy_value = 0;
if (noisy_value > 4095) noisy_value = 4095;
ADCS->last_conversion_value = (uint16_t)noisy_value;
// Çàïèñûâàåì â DR
ADCx->DR = ADCS->last_conversion_value;
// Óñòàíàâëèâàåì ôëàã EOC
// Устанавливаем EOS в конце последовательности
ADCx->SR |= ADC_SR_EOC;
// Îáðàáîòêà DMA
if (ADCx->CR2 & ADC_CR2_DMA) {
ADC_DMA_Transfer(ADCx, ADCS);
}
// Îáðàáîòêà ñêàíèðîâàíèÿ
if (ADCx->CR1 & ADC_CR1_SCAN) {
ADCS->current_rank++;
uint32_t seq_len = ADC_Get_Sequence_Length(ADCx);
if (ADCS->current_rank < seq_len) {
// Ñëåäóþùèé êàíàë â ïîñëåäîâàòåëüíîñòè
ADCS->current_channel = ADC_Get_Sequence_Channel(ADCx, ADCS->current_rank);
ADCS->conversion_time_elapsed = 0;
return;
}
else {
// Êîíåö ïîñëåäîâàòåëüíîñòè
#ifdef ADC_SR_EOS
ADCx->SR |= ADC_SR_EOS;
#endif
}
}
ADCS->conversion_time_elapsed = 0;
ADCS->conversion_time_elapsed = -1;
}
/////////////////////////////---TIMER TRIGGER SUPPORT---//////////////////////////
uint8_t ADC_Check_Timer_Trigger(ADC_TypeDef* ADCx, uint32_t trigger_source)
{
// Анализируем источник триггера из регистров ADC
switch (trigger_source) {
#ifdef ADC_EXTERNALTRIGCONV_T2_TRGO
case ADC_EXTERNALTRIGCONV_T2_TRGO:
return Slave_Channels.TIM2_TRGO;
#endif
#ifdef ADC_EXTERNALTRIGCONV_T3_TRGO
case ADC_EXTERNALTRIGCONV_T3_TRGO:
return Slave_Channels.TIM3_TRGO;
#endif
#ifdef ADC_EXTERNALTRIGCONV_T8_TRGO
case ADC_EXTERNALTRIGCONV_T8_TRGO:
return Slave_Channels.TIM8_TRGO;
#endif
#ifdef ADC_EXTERNALTRIGCONV_T1_CC1
case ADC_EXTERNALTRIGCONV_T1_CC1:
#endif
#ifdef ADC_EXTERNALTRIGCONV_T1_CC2
case ADC_EXTERNALTRIGCONV_T1_CC2:
#endif
#ifdef ADC_EXTERNALTRIGCONV_T1_CC3
case ADC_EXTERNALTRIGCONV_T1_CC3:
#endif
#ifdef ADC_EXTERNALTRIGCONV_T2_CC2
case ADC_EXTERNALTRIGCONV_T2_CC2:
#endif
#ifdef ADC_EXTERNALTRIGCONV_T2_CC3
case ADC_EXTERNALTRIGCONV_T2_CC3:
#endif
#ifdef ADC_EXTERNALTRIGCONV_T2_CC4
case ADC_EXTERNALTRIGCONV_T2_CC4:
#endif
#ifdef ADC_EXTERNALTRIGCONV_T3_CC1
case ADC_EXTERNALTRIGCONV_T3_CC1:
#endif
#ifdef ADC_EXTERNALTRIGCONV_T4_CC4
case ADC_EXTERNALTRIGCONV_T4_CC4:
#endif
#ifdef ADC_EXTERNALTRIGCONV_T5_CC1
case ADC_EXTERNALTRIGCONV_T5_CC1:
#endif
#ifdef ADC_EXTERNALTRIGCONV_T5_CC2
case ADC_EXTERNALTRIGCONV_T5_CC2:
#endif
#ifdef ADC_EXTERNALTRIGCONV_T5_CC3
case ADC_EXTERNALTRIGCONV_T5_CC3:
#endif
#ifdef ADC_EXTERNALTRIGCONV_T8_CC1
case ADC_EXTERNALTRIGCONV_T8_CC1:
#endif
#ifdef ADC_EXTERNALTRIGCONV_Ext_IT11
case ADC_EXTERNALTRIGCONV_Ext_IT11:
#endif
default:
return 0;
}
}
void ADC_Check_External_Trigger(ADC_TypeDef* ADCx, struct ADC_Sim* ADCS)
{
#ifdef STM32F1
// Для STM32F1 проверяем бит EXTTRIG
if (!(ADCx->CR2 & ADC_CR2_EXTTRIG)) return;
// Получаем источник триггера и фронт
uint32_t trigger_source = (ADCx->CR2 & ADC_CR2_EXTSEL); // Для F1 EXTSEL[2:0] биты 19:17
uint32_t trigger_edge = (ADCx->CR2 & ADC_CR2_EXTTRIG) ? 1 : 0; // Для F1 просто включен/выключен
#elif defined(STM32F4)
// Для STM32F4 проверяем EXTEN и EXTSEL
if (!(ADCx->CR2 & ADC_CR2_EXTEN)) return; // Для F4 проверяем EXTEN
// Получаем источник триггера и фронт
uint32_t trigger_source = (ADCx->CR2 & ADC_CR2_EXTSEL);
uint32_t trigger_edge = (ADCx->CR2 & ADC_CR2_EXTEN);
#else
return; // Неподдерживаемая платформа
#endif
uint8_t current_trigger_state = ADC_Check_Timer_Trigger(ADCx, trigger_source);
uint8_t trigger_occurred = 0;
#ifdef STM32F1
// Для F1 - простой rising edge при наличии триггера
if (trigger_edge) {
trigger_occurred = current_trigger_state && !ADCS->last_trigger_state;
}
#endif
#ifdef STM32F4
switch (trigger_edge)
{
case ADC_EXTERNALTRIGCONVEDGE_RISING:
trigger_occurred = current_trigger_state && !ADCS->last_trigger_state;
break;
case ADC_EXTERNALTRIGCONVEDGE_FALLING:
trigger_occurred = !current_trigger_state && ADCS->last_trigger_state;
break;
case ADC_EXTERNALTRIGCONVEDGE_RISINGFALLING:
trigger_occurred = (current_trigger_state && !ADCS->last_trigger_state) ||
(!current_trigger_state && ADCS->last_trigger_state);
break;
default:
break;
}
#endif
if (trigger_occurred) {
ADC_Start_Conversion(ADCx, ADCS);
}
ADCS->last_trigger_state = current_trigger_state;
}
/////////////////////////////---REGISTER-BASED FUNCTIONS---///////////////////
double ADC_Get_Total_Conversion_Time(ADC_TypeDef* ADCx, struct ADC_Sim* ADCS)
{
// Ïîëó÷àåì sampling time èç ðåãèñòðîâ
// Получаем sampling time из регистров
uint32_t sampling_cycles = ADC_Get_Sampling_Cycles(ADCx, ADCS->current_channel);
// Conversion cycles ôèêñèðîâàíû äëÿ ðàçðåøåíèÿ
uint32_t conversion_cycles = 12; // Äëÿ 12-bit
// Conversion cycles фиксированы для разрешения
uint32_t conversion_cycles = 12; // Для 12-bit
double total_cycles = sampling_cycles + conversion_cycles;
double adc_clock = ADCS->adc_clock_freq; // ×àñòîòà øèíû
double adc_clock = ADCS->adc_clock_freq; // Частота шины
return total_cycles / adc_clock;
}
double ADC_Get_Total_Sequence_Time(ADC_TypeDef* ADCx, struct ADC_Sim* ADCS)
{
uint32_t total_cycles = 0;
uint32_t seq_len = ADC_Get_Sequence_Length(ADCx);
for (uint32_t rank = 0; rank < seq_len; rank++) {
uint32_t channel = ADC_Get_Sequence_Channel(ADCx, rank);
uint32_t sampling_cycles = ADC_Get_Sampling_Cycles(ADCx, channel);
total_cycles += sampling_cycles + 12; // sampling + conversion
}
return total_cycles / ADCS->adc_clock_freq;
}
uint32_t ADC_Get_Sampling_Cycles(ADC_TypeDef* ADCx, uint32_t channel)
{
// Ïîëó÷àåì sampling time èç SMPR1/SMPR2
// Получаем sampling time из SMPR1/SMPR2
uint32_t smpr_code;
if (channel <= 9) {
smpr_code = (ADCx->SMPR2 >> (channel * 3)) & 0x7;
@@ -176,7 +312,7 @@ uint32_t ADC_Get_Sequence_Channel(ADC_TypeDef* ADCx, uint32_t rank)
}
/////////////////////////////---DMA FUNCTIONS---///////////////////////////////
void ADC_DMA_Transfer(ADC_TypeDef* ADCx, struct ADC_Sim* ADCS)
void ADC_DMA_Sim_Transfer(ADC_TypeDef* ADCx, struct ADC_Sim* ADCS)
{
if (!ADCS->dma_buffer || ADCS->dma_buffer_size == 0) return;

View File

@@ -5,11 +5,11 @@
#ifdef STM32F1
#define ADC_NOISE_LSB 10 // Шум в LSB (квантах АЦП)
#define ADC_NOISE_LSB 30 // Большой шум STMF103 в LSB (квантах АЦП)
#endif
#ifdef STM32F4
#define ADC_NOISE_LSB 2 // Шум в LSB (квантах АЦП)
#define ADC_NOISE_LSB 10 // Шум в LSB (квантах АЦП)
#endif
/////////////////////////////---STRUCTURES---///////////////////////////
@@ -32,6 +32,11 @@ struct ADC_Sim
// Timing
double simulation_step;
double adc_clock_freq;
// Добавьте для поддержки триггеров
uint8_t external_trigger_enabled;
uint32_t trigger_source;
uint8_t last_trigger_state;
};
///////////////////////////////////////////////////////////////////////
@@ -42,11 +47,13 @@ void ADC_Simulation(ADC_TypeDef* ADCx, struct ADC_Sim* ADCS);
void ADC_Start_Conversion(ADC_TypeDef* ADCx, struct ADC_Sim* ADCS);
void ADC_Complete_Conversion(ADC_TypeDef* ADCx, struct ADC_Sim* ADCS);
void ADC_Check_External_Trigger(ADC_TypeDef* ADCx, struct ADC_Sim* ADCS);
double ADC_Get_Total_Conversion_Time(ADC_TypeDef* ADCx, struct ADC_Sim* ADCS);
double ADC_Get_Total_Sequence_Time(ADC_TypeDef* ADCx, struct ADC_Sim* ADCS);
uint32_t ADC_Get_Sampling_Cycles(ADC_TypeDef* ADCx, uint32_t channel);
uint32_t ADC_Get_Sequence_Length(ADC_TypeDef* ADCx);
uint32_t ADC_Get_Sequence_Channel(ADC_TypeDef* ADCx, uint32_t rank);
void ADC_DMA_Transfer(ADC_TypeDef* ADCx, struct ADC_Sim* ADCS);
void ADC_DMA_Sim_Transfer(ADC_TypeDef* ADCx, struct ADC_Sim* ADCS);
void ADC_Set_Channel_Value(ADC_TypeDef* ADCx, uint32_t channel, double voltage);
void ADC_SIM_DEINIT(void);

View File

@@ -0,0 +1,591 @@
#include "stm32_matlab_dma.h"
#include <string.h>
// DMA stream simulation structures
#ifdef USE_DMA1
struct DMA_Stream_Sim dma1_stream0s;
struct DMA_Stream_Sim dma1_stream1s;
struct DMA_Stream_Sim dma1_stream2s;
struct DMA_Stream_Sim dma1_stream3s;
struct DMA_Stream_Sim dma1_stream4s;
struct DMA_Stream_Sim dma1_stream5s;
struct DMA_Stream_Sim dma1_stream6s;
struct DMA_Stream_Sim dma1_stream7s;
#endif
#ifdef USE_DMA2
struct DMA_Stream_Sim dma2_stream0s;
struct DMA_Stream_Sim dma2_stream1s;
struct DMA_Stream_Sim dma2_stream2s;
struct DMA_Stream_Sim dma2_stream3s;
struct DMA_Stream_Sim dma2_stream4s;
struct DMA_Stream_Sim dma2_stream5s;
struct DMA_Stream_Sim dma2_stream6s;
struct DMA_Stream_Sim dma2_stream7s;
#endif
void DMA_Call_IRQHandller(DMA_TypeDef* DMAx, uint32_t stream);
// Модифицируем основную функцию выполнения передачи
void DMA_Sim_Transfer(DMA_TypeDef* DMAx, uint32_t stream)
{
struct DMA_Stream_Sim* stream_sim = DMA_Get_Stream_Sim(DMAx, stream);
if (!stream_sim) return;
// Проверяем включен ли stream в регистрах
uint8_t hardware_enabled = DMA_Is_Stream_Enabled(DMAx, stream);
if (!hardware_enabled) {
// Если аппаратно выключен, сбрасываем состояние
if (stream_sim->enabled) {
memset(stream_sim, 0, sizeof(struct DMA_Stream_Sim));
}
return;
}
// Если аппаратно включен, инициализируем если нужно
if (!stream_sim->enabled) {
stream_sim->peripheral_address = DMA_Get_Peripheral_Address(DMAx, stream);
stream_sim->memory_address = DMA_Get_Memory_Address(DMAx, stream);
stream_sim->buffer_size = DMA_Get_Buffer_Size(DMAx, stream);
stream_sim->circular_mode = DMA_Get_Circular_Mode(DMAx, stream);
stream_sim->data_size = DMA_Get_DataSize(DMAx, stream); // Сохраняем размер данных
stream_sim->current_index = 0;
stream_sim->transfer_complete = 0;
stream_sim->enabled = 1;
stream_sim->transfer_enabled = 1;
}
// Проверяем нужно ли выполнить передачу
if (!stream_sim->transfer_enabled) return;
if (!stream_sim->peripheral_address || !stream_sim->memory_address) return;
// ВЫПОЛНЯЕМ ПЕРЕДАЧУ С УЧЕТОМ РАЗМЕРА ДАННЫХ
switch (stream_sim->data_size) {
case 1: // 8-bit data
{
uint8_t current_value = *(uint8_t*)stream_sim->peripheral_address;
((uint8_t*)stream_sim->memory_address)[stream_sim->current_index] = current_value;
}
break;
case 2: // 16-bit data
{
uint16_t current_value = *(uint16_t*)stream_sim->peripheral_address;
((uint16_t*)stream_sim->memory_address)[stream_sim->current_index] = current_value;
}
break;
case 4: // 32-bit data
{
uint32_t current_value = *(uint32_t*)stream_sim->peripheral_address;
((uint32_t*)stream_sim->memory_address)[stream_sim->current_index] = current_value;
}
break;
default: // По умолчанию 8-bit
{
uint8_t current_value = *(uint8_t*)stream_sim->peripheral_address;
((uint8_t*)stream_sim->memory_address)[stream_sim->current_index] = current_value;
}
break;
}
stream_sim->current_index++;
// Проверяем завершение передачи
if (stream_sim->current_index >= stream_sim->buffer_size) {
stream_sim->transfer_complete = 1;
if (stream_sim->circular_mode) {
stream_sim->current_index = 0;
} else {
stream_sim->transfer_enabled = 0;
stream_sim->enabled = 0;
DMA_Call_IRQHandller(DMAx, stream);
}
}
}
/////////////////////////////---HELPER FUNCTIONS---//////////////////////////
struct DMA_Stream_Sim* DMA_Get_Stream_Sim(DMA_TypeDef* DMAx, uint32_t stream)
{
#ifdef USE_DMA1
if (DMAx == DMA1) {
switch (stream) {
case 0: return &dma1_stream0s;
case 1: return &dma1_stream1s;
case 2: return &dma1_stream2s;
case 3: return &dma1_stream3s;
case 4: return &dma1_stream4s;
case 5: return &dma1_stream5s;
case 6: return &dma1_stream6s;
case 7: return &dma1_stream7s;
}
}
#endif
#ifdef USE_DMA2
if (DMAx == DMA2) {
switch (stream) {
case 0: return &dma2_stream0s;
case 1: return &dma2_stream1s;
case 2: return &dma2_stream2s;
case 3: return &dma2_stream3s;
case 4: return &dma2_stream4s;
case 5: return &dma2_stream5s;
case 6: return &dma2_stream6s;
case 7: return &dma2_stream7s;
}
}
#endif
return NULL;
}
uint8_t DMA_Is_Stream_Enabled(DMA_TypeDef* DMAx, uint32_t stream)
{
// Проверяем регистры DMA чтобы определить включен ли stream
#ifdef STM32F1
if (DMAx == DMA1) {
volatile uint32_t* cr_reg = NULL;
switch (stream) {
case 0: cr_reg = &DMA1_Channel1->CCR; break;
case 1: cr_reg = &DMA1_Channel2->CCR; break;
case 2: cr_reg = &DMA1_Channel3->CCR; break;
case 3: cr_reg = &DMA1_Channel4->CCR; break;
case 4: cr_reg = &DMA1_Channel5->CCR; break;
case 5: cr_reg = &DMA1_Channel6->CCR; break;
case 6: cr_reg = &DMA1_Channel7->CCR; break;
}
if (cr_reg) {
return (*cr_reg & DMA_CCR_EN) != 0;
}
}
#elif defined(STM32F4)
if (DMAx == DMA1) {
volatile uint32_t* cr_reg = NULL;
switch (stream) {
case 0: cr_reg = &DMA1_Stream0->CR; break;
case 1: cr_reg = &DMA1_Stream1->CR; break;
case 2: cr_reg = &DMA1_Stream2->CR; break;
case 3: cr_reg = &DMA1_Stream3->CR; break;
case 4: cr_reg = &DMA1_Stream4->CR; break;
case 5: cr_reg = &DMA1_Stream5->CR; break;
case 6: cr_reg = &DMA1_Stream6->CR; break;
case 7: cr_reg = &DMA1_Stream7->CR; break;
}
if (cr_reg) {
return (*cr_reg & DMA_SxCR_EN) != 0;
}
}
else if (DMAx == DMA2) {
volatile uint32_t* cr_reg = NULL;
switch (stream) {
case 0: cr_reg = &DMA2_Stream0->CR; break;
case 1: cr_reg = &DMA2_Stream1->CR; break;
case 2: cr_reg = &DMA2_Stream2->CR; break;
case 3: cr_reg = &DMA2_Stream3->CR; break;
case 4: cr_reg = &DMA2_Stream4->CR; break;
case 5: cr_reg = &DMA2_Stream5->CR; break;
case 6: cr_reg = &DMA2_Stream6->CR; break;
case 7: cr_reg = &DMA2_Stream7->CR; break;
}
if (cr_reg) {
return (*cr_reg & DMA_SxCR_EN) != 0;
}
}
#endif
return 0;
}
uint32_t* DMA_Get_Peripheral_Address(DMA_TypeDef* DMAx, uint32_t stream)
{
// Получаем адрес периферии из регистров DMA
#ifdef STM32F1
if (DMAx == DMA1) {
switch (stream) {
case 0: return (uint64_t*)DMA1_Channel1->CPAR;
case 1: return (uint64_t*)DMA1_Channel2->CPAR;
case 2: return (uint64_t*)DMA1_Channel3->CPAR;
case 3: return (uint64_t*)DMA1_Channel4->CPAR;
case 4: return (uint64_t*)DMA1_Channel5->CPAR;
case 5: return (uint64_t*)DMA1_Channel6->CPAR;
case 6: return (uint64_t*)DMA1_Channel7->CPAR;
}
}
#elif defined(STM32F4)
if (DMAx == DMA1) {
volatile uint64_t* par_reg = NULL;
switch (stream) {
case 0: par_reg = &DMA1_Stream0->PAR; break;
case 1: par_reg = &DMA1_Stream1->PAR; break;
case 2: par_reg = &DMA1_Stream2->PAR; break;
case 3: par_reg = &DMA1_Stream3->PAR; break;
case 4: par_reg = &DMA1_Stream4->PAR; break;
case 5: par_reg = &DMA1_Stream5->PAR; break;
case 6: par_reg = &DMA1_Stream6->PAR; break;
case 7: par_reg = &DMA1_Stream7->PAR; break;
}
if (par_reg) {
return (uint64_t*)*par_reg;
}
}
else if (DMAx == DMA2) {
volatile uint64_t* par_reg = NULL;
switch (stream) {
case 0: par_reg = &DMA2_Stream0->PAR; break;
case 1: par_reg = &DMA2_Stream1->PAR; break;
case 2: par_reg = &DMA2_Stream2->PAR; break;
case 3: par_reg = &DMA2_Stream3->PAR; break;
case 4: par_reg = &DMA2_Stream4->PAR; break;
case 5: par_reg = &DMA2_Stream5->PAR; break;
case 6: par_reg = &DMA2_Stream6->PAR; break;
case 7: par_reg = &DMA2_Stream7->PAR; break;
}
if (par_reg) {
return (uint64_t*)*par_reg;
}
}
#endif
return NULL;
}
uint32_t* DMA_Get_Memory_Address(DMA_TypeDef* DMAx, uint32_t stream)
{
// Получаем адрес памяти из регистров DMA
#ifdef STM32F1
if (DMAx == DMA1) {
switch (stream) {
case 0: return (uint64_t*)DMA1_Channel1->CPAR;
case 1: return (uint64_t*)DMA1_Channel2->CPAR;
case 2: return (uint64_t*)DMA1_Channel3->CPAR;
case 3: return (uint64_t*)DMA1_Channel4->CPAR;
case 4: return (uint64_t*)DMA1_Channel5->CPAR;
case 5: return (uint64_t*)DMA1_Channel6->CPAR;
case 6: return (uint64_t*)DMA1_Channel7->CPAR;
}
}
#elif defined(STM32F4)
if (DMAx == DMA1) {
volatile uint64_t* mar_reg = NULL;
switch (stream) {
case 0: mar_reg = &DMA1_Stream0->M0AR; break;
case 1: mar_reg = &DMA1_Stream1->M0AR; break;
case 2: mar_reg = &DMA1_Stream2->M0AR; break;
case 3: mar_reg = &DMA1_Stream3->M0AR; break;
case 4: mar_reg = &DMA1_Stream4->M0AR; break;
case 5: mar_reg = &DMA1_Stream5->M0AR; break;
case 6: mar_reg = &DMA1_Stream6->M0AR; break;
case 7: mar_reg = &DMA1_Stream7->M0AR; break;
}
if (mar_reg) {
return (uint64_t*)*mar_reg;
}
}
else if (DMAx == DMA2) {
volatile uint64_t* mar_reg = NULL;
switch (stream) {
case 0: mar_reg = &DMA2_Stream0->M0AR; break;
case 1: mar_reg = &DMA2_Stream1->M0AR; break;
case 2: mar_reg = &DMA2_Stream2->M0AR; break;
case 3: mar_reg = &DMA2_Stream3->M0AR; break;
case 4: mar_reg = &DMA2_Stream4->M0AR; break;
case 5: mar_reg = &DMA2_Stream5->M0AR; break;
case 6: mar_reg = &DMA2_Stream6->M0AR; break;
case 7: mar_reg = &DMA2_Stream7->M0AR; break;
}
if (mar_reg) {
return (uint64_t*)*mar_reg;
}
}
#endif
return NULL;
}
uint32_t DMA_Get_Buffer_Size(DMA_TypeDef* DMAx, uint32_t stream)
{
// Получаем размер буфера из регистров DMA
#ifdef STM32F1
if (DMAx == DMA1) {
switch (stream) {
case 0: return DMA1_Channel1->CNDTR;
case 1: return DMA1_Channel2->CNDTR;
case 2: return DMA1_Channel3->CNDTR;
case 3: return DMA1_Channel4->CNDTR;
case 4: return DMA1_Channel5->CNDTR;
case 5: return DMA1_Channel6->CNDTR;
case 6: return DMA1_Channel7->CNDTR;
}
}
#elif defined(STM32F4)
if (DMAx == DMA1) {
volatile uint64_t* mar_reg = NULL;
switch (stream) {
case 0: mar_reg = &DMA1_Stream0->NDTR; break;
case 1: mar_reg = &DMA1_Stream1->NDTR; break;
case 2: mar_reg = &DMA1_Stream2->NDTR; break;
case 3: mar_reg = &DMA1_Stream3->NDTR; break;
case 4: mar_reg = &DMA1_Stream4->NDTR; break;
case 5: mar_reg = &DMA1_Stream5->NDTR; break;
case 6: mar_reg = &DMA1_Stream6->NDTR; break;
case 7: mar_reg = &DMA1_Stream7->NDTR; break;
}
if (mar_reg) {
return (uint64_t*)*mar_reg;
}
}
else if (DMAx == DMA2) {
volatile uint64_t* mar_reg = NULL;
switch (stream) {
case 0: mar_reg = &DMA2_Stream0->NDTR; break;
case 1: mar_reg = &DMA2_Stream1->NDTR; break;
case 2: mar_reg = &DMA2_Stream2->NDTR; break;
case 3: mar_reg = &DMA2_Stream3->NDTR; break;
case 4: mar_reg = &DMA2_Stream4->NDTR; break;
case 5: mar_reg = &DMA2_Stream5->NDTR; break;
case 6: mar_reg = &DMA2_Stream6->NDTR; break;
case 7: mar_reg = &DMA2_Stream7->NDTR; break;
}
if (mar_reg) {
return (uint64_t*)*mar_reg;
}
}
#endif
return 0;
}
uint8_t DMA_Get_Circular_Mode(DMA_TypeDef* DMAx, uint32_t stream)
{
// Проверяем циклический режим
#ifdef STM32F1
if (DMAx == DMA1) {
switch (stream) {
case 0: return (DMA1_Channel1->CCR & DMA_CCR_CIRC) != 0;
case 1: return (DMA1_Channel2->CCR & DMA_CCR_CIRC) != 0;
case 2: return (DMA1_Channel3->CCR & DMA_CCR_CIRC) != 0;
case 3: return (DMA1_Channel4->CCR & DMA_CCR_CIRC) != 0;
case 4: return (DMA1_Channel5->CCR & DMA_CCR_CIRC) != 0;
case 5: return (DMA1_Channel6->CCR & DMA_CCR_CIRC) != 0;
case 6: return (DMA1_Channel7->CCR & DMA_CCR_CIRC) != 0;
}
}
if (DMAx == DMA1) {
switch (stream) {
case 0: return (DMA1_Stream1->CR & DMA_SxCR_CIRC) != 0;
case 1: return (DMA1_Stream11->CR & DMA_SxCR_CIRC) != 0;
case 2: return (DMA1_Stream13->CR & DMA_SxCR_CIRC) != 0;
case 3: return (DMA1_Stream14->CR & DMA_SxCR_CIRC) != 0;
case 4: return (DMA1_Stream15->CR & DMA_SxCR_CIRC) != 0;
case 5: return (DMA1_Stream16->CR & DMA_SxCR_CIRC) != 0;
case 6: return (DMA1_Stream17->CR & DMA_SxCR_CIRC) != 0;
}
}
#elif defined(STM32F4)
if (DMAx == DMA1 || DMAx == DMA2) {
volatile uint32_t* cr_reg = NULL;
switch (stream) {
case 0: return (DMA2_Stream1->CR & DMA_SxCR_CIRC) != 0;
case 1: return (DMA2_Stream1->CR & DMA_SxCR_CIRC) != 0;
case 2: return (DMA2_Stream3->CR & DMA_SxCR_CIRC) != 0;
case 3: return (DMA2_Stream4->CR & DMA_SxCR_CIRC) != 0;
case 4: return (DMA2_Stream5->CR & DMA_SxCR_CIRC) != 0;
case 5: return (DMA2_Stream6->CR & DMA_SxCR_CIRC) != 0;
case 6: return (DMA2_Stream7->CR & DMA_SxCR_CIRC) != 0;
}
}
#endif
return 0;
}
// функцию для определения размера данных DMA
uint32_t DMA_Get_DataSize(DMA_TypeDef* DMAx, uint32_t stream)
{
#ifdef STM32F4
if (DMAx == DMA1 || DMAx == DMA2) {
volatile uint32_t* cr_reg = NULL;
// Получаем регистр CR для соответствующего потока
if (DMAx == DMA1) {
switch (stream) {
case 0: cr_reg = &DMA1_Stream0->CR; break;
case 1: cr_reg = &DMA1_Stream1->CR; break;
case 2: cr_reg = &DMA1_Stream2->CR; break;
case 3: cr_reg = &DMA1_Stream3->CR; break;
case 4: cr_reg = &DMA1_Stream4->CR; break;
case 5: cr_reg = &DMA1_Stream5->CR; break;
case 6: cr_reg = &DMA1_Stream6->CR; break;
case 7: cr_reg = &DMA1_Stream7->CR; break;
}
}
else if (DMAx == DMA2) {
switch (stream) {
case 0: cr_reg = &DMA2_Stream0->CR; break;
case 1: cr_reg = &DMA2_Stream1->CR; break;
case 2: cr_reg = &DMA2_Stream2->CR; break;
case 3: cr_reg = &DMA2_Stream3->CR; break;
case 4: cr_reg = &DMA2_Stream4->CR; break;
case 5: cr_reg = &DMA2_Stream5->CR; break;
case 6: cr_reg = &DMA2_Stream6->CR; break;
case 7: cr_reg = &DMA2_Stream7->CR; break;
}
}
if (cr_reg) {
uint32_t psize = (*cr_reg & DMA_SxCR_PSIZE);
// Определяем размер данных на основе битов PSIZE
switch (psize) {
case DMA_PDATAALIGN_BYTE: // 00: Byte alignment (8-bit)
return 1;
case DMA_PDATAALIGN_HALFWORD: // 01: HalfWord alignment (16-bit)
return 2;
case DMA_PDATAALIGN_WORD: // 10: Word alignment (32-bit)
return 4;
default:
return 1; // По умолчанию байт
}
}
}
#elif defined(STM32F1)
// Для STM32F1 логика может отличаться
if (DMAx == DMA1) {
volatile uint32_t* ccr_reg = NULL;
switch (stream) {
case 0: ccr_reg = &DMA1_Channel1->CCR; break;
case 1: ccr_reg = &DMA1_Channel2->CCR; break;
case 2: ccr_reg = &DMA1_Channel3->CCR; break;
case 3: ccr_reg = &DMA1_Channel4->CCR; break;
case 4: ccr_reg = &DMA1_Channel5->CCR; break;
case 5: ccr_reg = &DMA1_Channel6->CCR; break;
case 6: ccr_reg = &DMA1_Channel7->CCR; break;
}
if (ccr_reg) {
// В STM32F1 размер определяется битами MSIZE[1:0] и PSIZE[1:0]
uint32_t size_bits = (*ccr_reg & (DMA_CCR_MSIZE | DMA_CCR_PSIZE));
// Упрощенная логика - обычно размеры памяти и периферии совпадают
if (size_bits & 0x0200) return 4; // Word (32-bit)
if (size_bits & 0x0100) return 2; // HalfWord (16-bit)
return 1; // Byte (8-bit)
}
}
#endif
return 1; // По умолчанию 1 байт
}
__weak void DMA1_Stream0_IRQHandler(void) {}
__weak void DMA1_Stream1_IRQHandler(void) {}
__weak void DMA1_Stream2_IRQHandler(void) {}
__weak void DMA1_Stream3_IRQHandler(void) {}
__weak void DMA1_Stream4_IRQHandler(void) {}
__weak void DMA1_Stream5_IRQHandler(void) {}
__weak void DMA1_Stream6_IRQHandler(void) {}
__weak void DMA1_Stream7_IRQHandler(void) {}
__weak void DMA2_Stream0_IRQHandler(void) {}
__weak void DMA2_Stream1_IRQHandler(void) {}
__weak void DMA2_Stream2_IRQHandler(void) {}
__weak void DMA2_Stream3_IRQHandler(void) {}
__weak void DMA2_Stream4_IRQHandler(void) {}
__weak void DMA2_Stream5_IRQHandler(void) {}
__weak void DMA2_Stream6_IRQHandler(void) {}
__weak void DMA2_Stream7_IRQHandler(void) {}
void DMA_Call_IRQHandller(DMA_TypeDef* DMAx, uint32_t stream)
{
struct DMA_Stream_Sim* stream_sim = DMA_Get_Stream_Sim(DMAx, stream);
if (stream_sim == NULL) return;
#ifdef STM32F4
// Определяем какой обработчик вызывать на основе DMAx и stream
if (DMAx == DMA1) {
switch (stream) {
case 0: DMA1_Stream0_IRQHandler(); break;
case 1: DMA1_Stream1_IRQHandler(); break;
case 2: DMA1_Stream2_IRQHandler(); break;
case 3: DMA1_Stream3_IRQHandler(); break;
case 4: DMA1_Stream4_IRQHandler(); break;
case 5: DMA1_Stream5_IRQHandler(); break;
case 6: DMA1_Stream6_IRQHandler(); break;
case 7: DMA1_Stream7_IRQHandler(); break;
}
}
else if (DMAx == DMA2) {
switch (stream) {
case 0: DMA2_Stream0_IRQHandler(); break;
case 1: DMA2_Stream1_IRQHandler(); break;
case 2: DMA2_Stream2_IRQHandler(); break;
case 3: DMA2_Stream3_IRQHandler(); break;
case 4: DMA2_Stream4_IRQHandler(); break;
case 5: DMA2_Stream5_IRQHandler(); break;
case 6: DMA2_Stream6_IRQHandler(); break;
case 7: DMA2_Stream7_IRQHandler(); break;
}
}
#elif defined(STM32F1)
if (DMAx == DMA1) {
switch (stream) {
case 0: DMA1_Channel0_IRQHandler(); break;
case 1: DMA1_Channel1_IRQHandler(); break;
case 2: DMA1_Channel2_IRQHandler(); break;
case 3: DMA1_Channel3_IRQHandler(); break;
case 4: DMA1_Channel4_IRQHandler(); break;
case 5: DMA1_Channel5_IRQHandler(); break;
case 6: DMA1_Channel6_IRQHandler(); break;
case 7: DMA1_Channel7_IRQHandler(); break;
}
}
#endif
}
/////////////////////////////---DEINITIALIZATION---/////////////////////////////
void DMA_SIM_DEINIT(void)
{
#ifdef USE_DMA1
memset(&dma1_stream0s, 0, sizeof(dma1_stream0s));
memset(&dma1_stream1s, 0, sizeof(dma1_stream1s));
memset(&dma1_stream2s, 0, sizeof(dma1_stream2s));
memset(&dma1_stream3s, 0, sizeof(dma1_stream3s));
memset(&dma1_stream4s, 0, sizeof(dma1_stream4s));
memset(&dma1_stream5s, 0, sizeof(dma1_stream5s));
memset(&dma1_stream6s, 0, sizeof(dma1_stream6s));
memset(&dma1_stream7s, 0, sizeof(dma1_stream7s));
#endif
#ifdef USE_DMA2
memset(&dma2_stream0s, 0, sizeof(dma2_stream0s));
memset(&dma2_stream1s, 0, sizeof(dma2_stream1s));
memset(&dma2_stream2s, 0, sizeof(dma2_stream2s));
memset(&dma2_stream3s, 0, sizeof(dma2_stream3s));
memset(&dma2_stream4s, 0, sizeof(dma2_stream4s));
memset(&dma2_stream5s, 0, sizeof(dma2_stream5s));
memset(&dma2_stream6s, 0, sizeof(dma2_stream6s));
memset(&dma2_stream7s, 0, sizeof(dma2_stream7s));
#endif
}

View File

@@ -0,0 +1,40 @@
#ifndef _MATLAB_DMA_H_
#define _MATLAB_DMA_H_
#include "stm32_matlab_conf.h"
#ifdef DMA1
#define USE_DMA1
#endif
#ifdef DMA2
#define USE_DMA2
#endif
/////////////////////////////---STRUCTURES---///////////////////////////
struct DMA_Stream_Sim
{
uint32_t* peripheral_address;
uint32_t* memory_address;
uint32_t buffer_size;
uint32_t current_index;
uint32_t data_size;
uint8_t circular_mode;
uint8_t transfer_complete;
uint8_t enabled;
uint8_t transfer_enabled;
};
///////////////////////////////////////////////////////////////////////
///////////////////////////---FUNCTIONS---///////////////////////////
void DMA_Sim_Transfer(DMA_TypeDef* DMAx, uint32_t stream);
struct DMA_Stream_Sim* DMA_Get_Stream_Sim(DMA_TypeDef* DMAx, uint32_t stream);
uint8_t DMA_Is_Stream_Enabled(DMA_TypeDef* DMAx, uint32_t stream);
uint32_t* DMA_Get_Peripheral_Address(DMA_TypeDef* DMAx, uint32_t stream);
uint32_t* DMA_Get_Memory_Address(DMA_TypeDef* DMAx, uint32_t stream);
uint32_t DMA_Get_Buffer_Size(DMA_TypeDef* DMAx, uint32_t stream);
uint8_t DMA_Get_Circular_Mode(DMA_TypeDef* DMAx, uint32_t stream);
uint32_t DMA_Get_DataSize(DMA_TypeDef* DMAx, uint32_t stream);
///////////////////////////////////////////////////////////////////////
#endif // _MATLAB_DMA_H_

View File

@@ -7,7 +7,7 @@
struct SlaveChannels Slave_Channels; // структура для связи и синхронизации таймеров
void TIM_Call_IRQHandller(TIM_TypeDef* TIMx);
//----------------------TIMER BASE FUNCTIONS-----------------------//
/* Базовая функция для симуляции таймера: она вызывается каждый шаг симуляции */
@@ -24,6 +24,7 @@ switch (TIMx->SMCR & TIM_SMCR_SMS) // TIMER MODE
case(TIM_SLAVEMODE_DISABLE):// NORMAL MODE counting
TIMx_Count(TIMx, TIMS);
Channels_Simulation(TIMx, TIMS); // CaptureCompare and PWM channels simulation
Write_TRGO(TIMx, TIMS);
break;
@@ -32,6 +33,7 @@ switch (TIMx->SMCR & TIM_SMCR_SMS) // TIMER MODE
Slave_Mode_Check_Source(TIMx, TIMS);
TIMx_Count(TIMx, TIMS);
Channels_Simulation(TIMx, TIMS); // CaptureCompare and PWM channels simulation
Write_TRGO(TIMx, TIMS);
break;
}
@@ -48,12 +50,14 @@ void TIMx_Count(TIM_TypeDef* TIMx, struct TIM_Sim* TIMS)
/* Проверка на переполнение и дальнейшая его обработка */
void Overflow_Check(TIM_TypeDef* TIMx, struct TIM_Sim* TIMS)
{
TIMS->Updated = 0;
// Переполнение таймера: сброс таймера и вызов прерывания
if ((TIMx->CR1 & TIM_CR1_UDIS) == 0) // UPDATE enable
{
if ((TIMx->CR1 & TIM_CR1_ARPE) == 0) TIMS->RELOAD = TIMx->ARR; // PRELOAD disable - update ARR every itteration
if (TIMS->tx_cnt > TIMS->RELOAD || TIMS->tx_cnt < 0) // OVERFLOW
{
TIMS->Updated = 1;
TIMS->RELOAD = TIMx->ARR; // RELOAD ARR
if (TIMS->tx_cnt > TIMx->ARR) // reset COUNTER
@@ -61,7 +65,7 @@ void Overflow_Check(TIM_TypeDef* TIMx, struct TIM_Sim* TIMS)
else if (TIMS->tx_cnt < 0)
TIMS->tx_cnt += TIMS->RELOAD+1;
call_IRQHandller(TIMx); // call HANDLER
TIM_Call_IRQHandller(TIMx); // call HANDLER
}
}
}
@@ -79,8 +83,6 @@ void Channels_Simulation(TIM_TypeDef* TIMx, struct TIM_Sim* TIMS)
CC_PWM_Ch4_Simulation(TIMx, TIMS);
Write_OC_to_GPIO(TIMx, TIMS);
Write_OC_to_TRGO(TIMx, TIMS);
}
//-----------------CAPTURE COPMARE & PWM FUNCTIONS------------------//
/* Выбор режима CaptureCompare или PWM и симуляция для каждого канала */
@@ -323,26 +325,38 @@ void Write_OC_to_GPIO(TIM_TypeDef *TIMx, struct TIM_Sim *TIMS)
}
}
/* Запись результата compare в глабальную структуру с TRIGGER OUTPUT */
void Write_OC_to_TRGO(TIM_TypeDef* TIMx, struct TIM_Sim* TIMS)
void Write_TRGO(TIM_TypeDef* TIMx, struct TIM_Sim* TIMS)
{
// write trigger output from OCxREF pin if need
unsigned temp_trgo;
if ((TIMx->CR2 & TIM_CR2_MMS) == (0b100 << TIM_CR2_MMS_Pos))
if ((TIMx->CR2 & TIM_CR2_MMS) == (TIM_TRGO_OC1REF))
{
temp_trgo = TIMS->Channels.OC1REF;
}
else if ((TIMx->CR2 & TIM_CR2_MMS) == (0b101 << TIM_CR2_MMS_Pos))
else if ((TIMx->CR2 & TIM_CR2_MMS) == (TIM_TRGO_OC2REF))
{
temp_trgo = TIMS->Channels.OC2REF;
}
else if ((TIMx->CR2 & TIM_CR2_MMS) == (0b110 << TIM_CR2_MMS_Pos))
else if ((TIMx->CR2 & TIM_CR2_MMS) == (TIM_TRGO_OC3REF))
{
temp_trgo = TIMS->Channels.OC3REF;
}
else if ((TIMx->CR2 & TIM_CR2_MMS) == (0b111 << TIM_CR2_MMS_Pos))
else if ((TIMx->CR2 & TIM_CR2_MMS) == (TIM_TRGO_OC4REF))
{
temp_trgo = TIMS->Channels.OC4REF;
}
else if ((TIMx->CR2 & TIM_CR2_MMS) == (TIM_TRGO_UPDATE))
{
temp_trgo = TIMS->Updated;
}
else if ((TIMx->CR2 & TIM_CR2_MMS) == (TIM_TRGO_ENABLE))
{
temp_trgo = (TIMx->CR1 & TIM_CR1_CEN) ? 1: 0;
}
else if ((TIMx->CR2 & TIM_CR2_MMS) == (TIM_TRGO_RESET))
{
temp_trgo = 0;
}
// select TIMx TRGO
@@ -585,7 +599,7 @@ void TIM_SIM_DEINIT(void)
//#endif
/* Вызов прерывания */
void call_IRQHandller(TIM_TypeDef* TIMx)
void TIM_Call_IRQHandller(TIM_TypeDef* TIMx)
{ // calling HANDLER
//if (TIMx == TIM1)
// TIM1_UP_IRQHandler();

View File

@@ -42,7 +42,7 @@ struct SlaveChannels
unsigned TIM8_TRGO : 1;
};
extern struct SlaveChannels Slave_Channels; // структура для связи и синхронизации таймеров
/* Структура для моделирования каналов таймера */
struct Channels_Sim
{
@@ -69,6 +69,7 @@ struct Channels_Sim
/* Структура для моделирования таймера */
struct TIM_Sim
{
int Updated; // счетчик таймера
double tx_cnt; // счетчик таймера
double tx_step; // шаг счета за один шаг симуляции
int RELOAD; // буфер, если PRELOAD = 1
@@ -87,8 +88,6 @@ void TIM_Simulation(TIM_TypeDef *TIMx, struct TIM_Sim *TIMS);
void TIMx_Count(TIM_TypeDef* TIMx, struct TIM_Sim* TIMS);
/* Проверка на переполнение и дальнейшая его обработка */
void Overflow_Check(TIM_TypeDef* TIMx, struct TIM_Sim* TIMS);
/* Вызов прерывания */
void call_IRQHandller(TIM_TypeDef *TIMx);
//-----------------------------------------------------------------//
@@ -104,7 +103,7 @@ void CC_PWM_Ch4_Simulation(TIM_TypeDef* TIMx, struct TIM_Sim* TIMS);
/* Запись каналов таймера в порты GPIO */
void Write_OC_to_GPIO(TIM_TypeDef* TIMx, struct TIM_Sim* TIMS);
/* Запись результата compare в глабальную структуру с TRIGGER OUTPUT */
void Write_OC_to_TRGO(TIM_TypeDef* TIMx, struct TIM_Sim* TIMS);
void Write_TRGO(TIM_TypeDef* TIMx, struct TIM_Sim* TIMS);
//------------------------------------------------------------------//