Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Microbalze MCS и программируемый таймер
Форум разработчиков электроники ELECTRONIX.ru > Программируемая логика ПЛИС (FPGA,CPLD, PLD) > Системы на ПЛИС - System on a Programmable Chip (SoPC)
Weyland
Здравствуйте. Пытаюсь освоить работу с Programmable Interval Timer в Microbalze Micro Controller System (v1.0). Написал программу суть которой сводится к обработке прерывания (нажатие кнопки на плате) и вывод на шину IO Bus подряд двух разных значений. Программа работает и я с помощью CHipScope Analyzer вижу что между импульсами записи 7 тактов. Далее хочу вставить задержку между обращениями на шину. За основу взял кусок кода из примера http://www.fpgadeveloper.com/2008/10/micro...lcd-driver.html, переделал его перед библиотеку XIOModule и вставляю в свой код обращение к функции delay_us. Тут для меня начинаются непонятки: расстояние между испульсами увеличивается, но связать его со значением которое отправляю в функцию не получается. Отправлял 1 и 10, расстояние между импульсами в обоих случаях равно 273 тактам. При генерации ядра Microbalze MCS для Programmable Interval Timer 1 выбрал такие настойки: Use Timer - вкл., Number of Bits for Timer - 32, Shall Counter Value Be Readable - вкл., Define Prescaler - None, Generate Interrupt - выкл. Далее привожу код:

Код
#include <stdio.h>
#include "platform.h"
#include "XIOModule.h"

#define IOBUS_write_fifo       (*(volatile u32 *) 0xC0000000)

XIOModule DelayTimer;

void delay_us(u32 time);

void myISR( void )
{
        IOBUS_write_fifo = 0xA;
        delay_us(1);
        IOBUS_write_fifo = 0xB;
}

int main()
{
    init_platform();

    u32 uGpi0;
    //external interrupt
    u8  uIntrId = 16;//XPAR_IOMODULE_0_SYSTEM_INTC_INTERRUPT_0_INTR;

    XIOModule NfdsIOMdule;

    XIOModule_Initialize(&NfdsIOMdule, XPAR_IOMODULE_0_DEVICE_ID);
    XIOModule_Start(&NfdsIOMdule);

    // Initialize the Timer
    u32 status;
    status = XIOModule_Timer_Initialize(&DelayTimer, XPAR_IOMODULE_0_DEVICE_ID);
    if (status != XST_SUCCESS){
        xil_printf("Timer failed to initialize\r\n");
        return XST_FAILURE;
    }

    XIOModule_Timer_SetOptions(&DelayTimer, 0, XTC_INT_MODE_OPTION);

    microblaze_register_handler(XIOModule_DeviceInterruptHandler, XPAR_IOMODULE_0_DEVICE_ID);
    XIOModule_Connect(&NfdsIOMdule, uIntrId, myISR, XPAR_IOMODULE_0_DEVICE_ID);
    XIOModule_Enable(&NfdsIOMdule, uIntrId);

    microblaze_enable_interrupts();

    while(1)
    {
        uGpi0 = XIOModule_DiscreteRead(&NfdsIOMdule, 1); //read gpio (Slide Switches)
        XIOModule_DiscreteWrite(&NfdsIOMdule, 1, uGpi0); //write gpio (Discrete LEDs)
    }

    cleanup_platform();

    return 0;
}

void delay_us(u32 time)
{
    XIOModule_SetResetValue(&DelayTimer, 0, time);
    XIOModule_Timer_Start(&DelayTimer, 0);
    while(!(XIOModule_IsExpired(&DelayTimer, 0))){}
    XIOModule_Timer_Stop(&DelayTimer, 0);
}


В моем понимании обращение delay_us(1) должно давать задержку в 1 такт или я не прав?
Golikov A.
us - это микросекунды... потому скорее в 1 микросекунду...
хотя по коду реально 1 тик таймера. Может во время генережки вы ему указали быть микросекундным таймером?
Опять же вопрос оптимизации, может так оказаться что у вас настолько медленно работает проц, что меньше 273 тиков таймера он отловить не может, попробуйте кратные значения 274 - 548 - 1096 и так далее, ну и 274-275 - 276 -277 тоже может быть интересно
dm.pogrebnoy
Может что конечно не понял всей затеи автора, но зачем вам две версии структуры для IOModule. Когда вы инициализируете таймер вы должны пользоваться ранее тнициализированной структурой IOModule, в ваши случае HfdsIOModule. В функцию задержки передавать ссылку на эту структуру или сделать ее глобальной.
Weyland
Golikov A, dm.pogrebnoy спасибо за ответы
Цитата
us - это микросекунды... потому скорее в 1 микросекунду...

да, в исходном примере эта функция использовалась для задержки в микросекундах, но в коде было time * 125 (частота тактирования микроблейза там равна 125 МГц). В моем случае тактовая частота равна 50 МГц, для удобства наблюдения задержки в чипскопе я ее сократил.
Цитата
Может во время генережки вы ему указали быть микросекундным таймером?

Нет, при генерации ядра в коргенераторе для таймера доступны только те параметры, которые я указал.
Цитата
Опять же вопрос оптимизации, может так оказаться что у вас настолько медленно работает проц, что меньше 273 тиков таймера он отловить не может

Частота тактирования равна 50 МГц.
Цитата
Может что конечно не понял всей затеи автора, но зачем вам две версии структуры для IOModule.

Просто изначально я практиковался с обработчиком прерываний и в уже в отлаженую программу вставил пример работы с таймером rolleyes.gif . Также мне казалось, что наличие 2-х функций (XIOModule_Initialize и XIOModule_Timer_Initialize) не просто так. Вы хотите сказать, что по сути эти 2 функции делают аналогичное? Я только в начале пути освоения Микроблейза, да и в Си уже давно не практиковался, поэтому критика и пояснение работы кода только приветствуется.
Golikov A.
ну так возьмите да поглядите, все исходники драйверов есть. По сути своей все их драйверы перекладывают структуры, да в нужные адреса модулей обращаются. Можно все вообще без драйверов сделать.

Кстати что микроблайз тактируется 50 МГц совсем не значит что он 50 миллионов инструкций в секунду выполняет, обращение по шинам не 1 такт, выбор из памяти, кеши, там все так можно завернуть - на троить, что проц просто стоять будет!

вот у меня так таймер работает
CODE

static XTmrCtr _TimerCounter; //структура настройки Таймера
XTmrCtr *TimerCounter = &(_TimerCounter); //указатель для удобства использования функций

//Инициализируем таймер
InitStatus = XTmrCtr_Initialize(TimerCounter, XPAR_ETHERNET_TIMER_DEVICE_ID);

//если устройство запущено, его надо установить и заново запустить инициализацию
if(InitStatus == XST_DEVICE_IS_STARTED)
{
print("\r\nРучная остановка таймера");
//надо получить данные настройки таймера вручную
XTmrCtr_Config *TmrCtrConfigPtr;
TmrCtrConfigPtr = XTmrCtr_LookupConfig(XPAR_ETHERNET_TIMER_DEVICE_ID);
if(TmrCtrConfigPtr!=NULL)
{
print("\r\nПолучение структуры таймера");
//заполняем настройки
TimerCounter->BaseAddress = TmrCtrConfigPtr->BaseAddress;
TimerCounter->IsReady = XIL_COMPONENT_IS_READY;
XTmrCtr_Stop(TimerCounter,0); //останавливаем 0 канал
XTmrCtr_Stop(TimerCounter,1); //останавливаем 1 канал
}
//сбрасываем настройки
TimerCounter->BaseAddress = 0;
TimerCounter->IsReady = 0;

print("\r\nПовторная инициализация таймера");
//инициализируем заново
InitStatus = XTmrCtr_Initialize(TimerCounter, XPAR_ETHERNET_TIMER_DEVICE_ID);
}

if(InitStatus != XST_SUCCESS)
xil_printf("\r\nОшибка инициализации таймера: %d",InitStatus);
else
{
InitStatus = XTmrCtr_SelfTest(TimerCounter, 0);
if(InitStatus != XST_SUCCESS)
xil_printf("\r\nОшибка самотестирования таймера: %d",InitStatus);
else
print("\r\nТаймер: OK!");


//настраиваем самоперезагрузку 0 таймера, и включаем прерывание
XTmrCtr_SetOptions(TimerCounter, 0, XTC_AUTO_RELOAD_OPTION|XTC_INT_MODE_OPTION);

//настраиваем самоперезагрузку 1 таймера, и включаем прерывание
XTmrCtr_SetOptions(TimerCounter, 1, XTC_AUTO_RELOAD_OPTION|XTC_INT_MODE_OPTION);


//задаим начальное значение таким, это время до прерывания
//0 канал
XTmrCtr_SetResetValue(TimerCounter, 0, TIMER_250MS_INTERVAL); //250 мСек
//XTmrCtr_SetResetValue(TimerCounter, 0, TIMER_10MS_INTERVAL); //10 мСек

//1 канал
XTmrCtr_SetResetValue(TimerCounter, 1, TIMER_500MS_INTERVAL); //500 мСек

//подключаем обработчик прерывания
XTmrCtr_SetHandler(TimerCounter,(XTmrCtr_Handler)InterruptHandler_Timer,(void *)TimerCounter);
}



может будет полезно, простите привожу кусок как есть...
да вспомнил что таймер у них к нулю считает, как то так...
dm.pogrebnoy
Цитата(Weyland @ Apr 5 2014, 19:00) *
Также мне казалось, что наличие 2-х функций (XIOModule_Initialize и XIOModule_Timer_Initialize) не просто так. Вы хотите сказать, что по сути эти 2 функции делают аналогичное? Я только в начале пути освоения Микроблейза, да и в Си уже давно не практиковался, поэтому критика и пояснение работы кода только приветствуется.

В микроконтроллере все упрощено, по сравнению с большим микроблейзом. Там посадили на быструю шину LMB аппаратный модуль который отвечает за все сразу. Т.е. сначала инициализируется этот модуль, а потом уже остальные его подсистемы по желанию. В том числе таймеры, прерывания, модуль асинхронного приемопередатчика. Для инициализации всего служит всего одна структура IOModule.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.