Всякие фиксы модели и заготовки для АЦП
И почему то все равно MATLAB намертво блокирует mingw64.... Приходится перезапускать матлаб для перекомпиляции
This commit is contained in:
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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_
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
//------------------------------------------------------------------//
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user