Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
SP_Lab_2_otchet (1).docx
Скачиваний:
26
Добавлен:
10.05.2015
Размер:
3.22 Mб
Скачать

Отчет по выполнению лабораторных работ

по дисциплине «Сигнальные процессоры»

Лабораторная работа № 2

Периферийные модули процессоров ARMCortex-M4 и их использование при вводе, выводе, обработке сигналов

Выполнил студент: Дата выполнения:

1. Высокоскоростная передача через порты общего назначения.

Вариант передачи

Процедура на языке Си

Процедура на языке ассемблера

Прямой доступ к памяти (DMA)

Число изменений контрольной индикации за … с

38

84

106

Частота контрольной индикации, Гц

0.76

1.68

2.12

Число циклов вывода за период изменения индикации

10240000

10240000

10240000

Частота вывода, МГц

7.7824

17.2032

21.7088

Скорость вывода, Мбайт/с

15.5648

34.4064

43.4176

Число процессорных тактов между выводами

21.59

9.77

7.74

Число исполняемых команд между выводами

-

-

При наличии осциллографических измерений:

Период вывода кодов, нс

120

60

44

Скорость вывода, Мбайт/с

16.67

33.3

45.45

Выводы

Язык Си-маленькая скорость передачи

Ассемблер-Скорость выше чем на Си

Прямой доступ-превосходит в скорости оба варианта

Домашнее задание

Скорректировать программу с целью реализации передачи информации с заданной скоростью: Кбайт/с по одному из программных вариантов и варианту с DMA.

Текст программы

Исходный модуль D:\ARM\Work\DspLab_2_1\main.c

//---------------------------------------------------------------------------

//

// УЧЕБНЫЙ ПРОЕКТ

// Высокоскоростной ввод-вывод через порты общего назначения (параллельный интерфейс)

// Copyright (C) 2013 МГТУ МИРЭА

//

//---------------------------------------------------------------------------

// Заголовочные файлы

#include "stm32_p407.h" //Файл конфигурации отладочной платы STM32-P407

#include "values.h" //Числовые значения исходных операндов

//Прототипы функций, определенных в этом файле

void PortEInitialize(void);

__asm void BufferToOutput(GPIO_TypeDef* GPIOx, uint16_t* data_pointer, uint32_t number);

void DMAInitialize(void);

//Глобальные параметры

uint16_t MemoryBuffer[BUFLENGTH]; //Буфер выводимых данных

const int CyclesNumber = CYCLESNUM; //Число циклов вывода буфера (константа)

volatile int CyclesCounter; //Счетчик числа циклов вывода буфера - используется

// только в режиме DMA

//---------------------------------------------------------------------------

// ГЛАВНАЯ ФУНКЦИЯ

int main()

{

//Текущие переменные

int i, j; //Переменные цикла

uint16_t* pMemBuffer; //Указатель на буфер

//Инициализация органов управления

STM_PBInit(BUTTON_DOWN, BUTTON_MODE_GPIO); //Позиция джойстика "вниз"

STM_PBInit(BUTTON_UP, BUTTON_MODE_GPIO); //Позиция джойстика "вверх"

STM_PBInit(BUTTON_WAKEUP, BUTTON_MODE_GPIO); //Кнопка WAKEUP выхода из программы

//Инициализация светодиодных индикаторов

STM_LEDInit(LED3); //"Красный"

STM_LEDInit(LED4); //"Зеленый"

//Программирование порта для вывода данных

PortEInitialize();

//Конфигурирование режима прямого доступа к памяти

DMAInitialize();

//Заполнение буфера отладочными кодами

for (i = 0; i < sizeof(MemoryBuffer)/4; i++) *((uint32_t*)MemoryBuffer + i) = 0x5555AAAA;

//Цикл основной программы

while (1)

{

if (STM_PBGetState(BUTTON_DOWN)) //Если джойстик в положении "вниз"

//Передача с использованием подпрограммы на языке Си

for (j = 0; j < CyclesNumber; j++) //Внешний цикл повторений передачи буфера

{ pMemBuffer = MemoryBuffer; //Указатель - на начало буфера

i = sizeof(MemoryBuffer)/2; //Число выводимых кодов

while (--i) GPIO_Write(GPIOE, *pMemBuffer++); //Внутренний цикл передачи буфера

}

else

if (!STM_PBGetState(BUTTON_UP)) //Если джойстик в исходном состоянии

//Передача с использованием подпрограммы на языке ассемблера

for (j = 0; j < CyclesNumber; j++) //Внешний цикл повторений передачи буфера

{ pMemBuffer = MemoryBuffer; //Указатель - на начало буфера

i = sizeof(MemoryBuffer)/2; //Число выводимых кодов

BufferToOutput(GPIOE, pMemBuffer, i); //Внутренний цикл передачи буфера

}

else //Джойстик в положении "вверх"

//Передача с использованием режима прямого доступа к памяти

{ CyclesCounter = 0; //Обнуление счетчика числа повторений передачи

TIM_Cmd(TIM8, ENABLE); //Разрешение обмена

while (CyclesCounter < CyclesNumber) __WFI(); //Ожидание (в спящем режиме) окончания передачи

TIM_Cmd(TIM8, DISABLE); //Остановка обмена

}

//Переключение индикации

STM_LEDToggle(LED4);

//Проверка нажатия кнопки WAKEUP, если нажата, сброс процессора

if (STM_PBGetState(BUTTON_WAKEUP)) NVIC_SystemReset();

}

}

//---------------------------------------------------------------------------

// ПОДПРОГРАММА ВЫВОДА БУФЕРА (на языке ассемблера)

// При вызове подпрограммы входные параметры загружаются соответственно в регистры R0, R1, R2,

// адрес возврата записан в регистре LR

__asm void BufferToOutput( //Входные параметры:

GPIO_TypeDef* GPIOx, //Базовый адрес порта (R0)

uint16_t* data_pointer, //Указатель на выводимые данные (R1)

uint32_t number) //Число циклов вывода (R2)

{

label

LDRH R3,[R1],#0x02 //Чтение полуслова из памяти с адресом в R1 в регистр R2

// с последующим увеличением содержимого R1 на 2

STR R3,[R0,#0x14] //Пересылка из регистра R3 по адресу (R0 + 0x14) -

// адресу выходного регистра порта

SUBS R2,R2,#1 //Уменьшение содержимого регистра R2 на 1 с установкой признаков

BNE label //Если не 0, переход на команду с меткой label

BX LR //Возврат в вызывающую программу по адресу в регистре связи LR

}

//---------------------------------------------------------------------------

// ПРОГРАММИРОВАНИЕ ПОРТА ОБЩЕГО НАЗНАЧЕНИЯ PE

void PortEInitialize(void)

{

GPIO_InitTypeDef GPIO_InitStructure; //Структура конфигурации портов общего назначения

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE); //Разрешение тактирования порта

GPIO_InitStructure.GPIO_Pin = 0xFF87; //Маска на выходные разряды (разряды 3..6 не исп.)

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; //Режим: вывод

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; //Задание быстродействия (2MHz, 25MHz, 50MHz, 100MHz)

GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //Установка типа выходного каскада: двухтактный

GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; //Подтягивающий резистор: нет

GPIO_Init(GPIOE, &GPIO_InitStructure); //Функция конфигурирования

}

//---------------------------------------------------------------------------

// КОНФИГУРИРОВАНИЕ ВЫВОДА В ПОРТ В РЕЖИМЕ ПРЯМОГО ДОСТУПА К ПАМЯТИ

// Каждая транзакция (передача кода) инициируется событием перезагрузки таймера.

// Общий старт и остановка процесса осуществляются в основной программе.

// Для подсчета числа передач задействовано прерывание, возникающее по окончании

// передачи всего буфера.

void DMAInitialize(void)

{

TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; //Структура конфигурации базового таймера

DMA_InitTypeDef DMA_InitStructure; //Структура конфигурации канала DMA

NVIC_InitTypeDef NVIC_InitStructure; //Структура конфигурации прерываний

//Конфигурирование таймера - источника запуска DMA-транзакций

RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM8, ENABLE); //Разрешение тактирования таймера

TIM_TimeBaseStructure.TIM_Period = 4; //Основной коэф. деления

TIM_TimeBaseStructure.TIM_Prescaler = 0; //Коэффициент предделения

TIM_TimeBaseStructure.TIM_ClockDivision = 0; //Делитель для входного фильтра (не используется)

TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //Режим счета вверх: от 0 до TIM_Period

TIM_TimeBaseStructure.TIM_RepetitionCounter = 0; //Счетчик повторов (не используется)

TIM_TimeBaseInit(TIM8, &TIM_TimeBaseStructure); //Функция конфигурирования

//Конфигурирование канала DMA

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE); //Разрешение тактирования контроллера DMA

DMA_DeInit(DMA2_Stream1); //Начальная установка (сброс) канала

DMA_InitStructure.DMA_Channel = DMA_Channel_7; //Номер источника запроса для канала

DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&GPIOE->ODR); //Адрес периферийного устройства (порта)

DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)MemoryBuffer; //Адрес буфера памяти

DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; //Направление передачи: память -> периферия

DMA_InitStructure.DMA_BufferSize = sizeof(MemoryBuffer)/2; //Число транзакций для передачи всего буфера

DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //Автоувеличение адреса периферии: нет

DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //Автоувеличение адреса памяти: да

DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; //Размер транзакции для памяти: полуслово

DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_HalfWord; //Размер транзакции для периферии: полуслово

DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; //Режим передачи буфера: циклический

DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh; //Уровень приоритета: наивысший

DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; //Использование промежуточного FIFO: нет

DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full; //Порог для FIFO (здесь не используется)

DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; //Размер пакета для памяти: одиночный

DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; //Размер пакета для периферии: одиночный

DMA_Init(DMA2_Stream1, &DMA_InitStructure); //Функция конфигурирования

TIM_DMACmd(TIM8, TIM_DMA_Update, ENABLE); //Выбор источника и вида запуска: таймер 8

// и событие его перезагрузки

DMA_Cmd(DMA2_Stream1, ENABLE); //Разрешение работы канала DMA

//Конфигурирование прерывания по окончании DMA (обработчик: DMA2_Stream1_IRQHandler)

DMA_ITConfig(DMA2_Stream1, DMA_IT_TC, ENABLE); //Тип прерывания от DMA: окончание передачи буфера

NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream1_IRQn; //Номер источника запроса прерывания

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 4; //Уровень приоритета (0 - высший, 15 - низший)

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //Приоритет внутри группы

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //Разрешение прерывания

NVIC_Init(&NVIC_InitStructure); //Функция конфигурирования

}

//---------------------------------------------------------------------------

// ОБСЛУЖИВАНИЕ ПРЕРЫВАНИЯ ОТ КОНТРОЛЛЕРА DMA ПО ЗАВЕРШЕНИИ ПЕРЕДАЧИ БУФЕРА

void DMA2_Stream1_IRQHandler(void)

{

DMA_ClearITPendingBit(DMA2_Stream1, DMA_IT_TCIF1); //Очистка флага запроса

CyclesCounter++; //Увеличение счетчика числа повторов передачи буфера

} // (проверяется в основной программе)

//---------------------------------------------------------------------------

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]