Мы снова в эфире и снова рассказываем о процессе боевых действий КБ13 против платы АЦП.
Борьба со временем.
С утра пришлось взять в руки секундомер — время снятия замеров всех 16 каналов АЦП не соответсвовало заявленным 10 мкс, а занимало где-то 60-70 мкс, что, конечно же, многовато при наших возможностях.
Оптимизация времени считывания пошла несколькими путями:
- разгон процессора;
- уменьшение таймингов на сигналы чипселекта, рида и пульса;
- увеличение частоты выдачи чипселекта и рида контроллером.
Прежде всего мы уменьшили тайминги шины EBI, на которой висят АЦП — выставив их в соответствии с даташитом для AD7656:
// NCS setup time. Unit: ns.
#define NCS_RD_SETUP 6
// NCS pulse time. Unit: ns.
#define NCS_RD_PULSE 40
// NCS hold time. Unit: ns.
#define NCS_RD_HOLD 10
// NRD setup time. Unit: ns.
#define NRD_SETUP 6
// NRD pulse time. Unit: ns.
#define NRD_PULSE 40
// NRD hold time. Unit: ns.
#define NRD_HOLD 10
// Read cycle time. Unit: ns.
#define NRD_CYCLE Max((NCS_RD_SETUP + NCS_RD_PULSE + NCS_RD_HOLD),(NRD_SETUP + NRD_PULSE + NRD_HOLD))
Далее настала очередь процессора.
Изначально инициализация системных часов происходила следующим образом:
#define FOSC0 12000000 //!< Osc0 frequency: Hz.
#define OSC0_STARTUP AVR32_PM_OSCCTRL0_STARTUP_2048_RCOSC //!< Osc0 startup time: RCOsc periods.
#define APPLI_CPU_SPEED 24000000
#define APPLI_PBA_SPEED 24000000
pm_freq_param_t pm_freq_param=
{
.cpu_f = APPLI_CPU_SPEED,
.pba_f = APPLI_PBA_SPEED,
.osc0_f = FOSC0,
.osc0_startup = OSC0_STARTUP
};
void init(void)
{
pm_configure_clocks(&pm_freq_param);
init_dbg_rs232(pm_freq_param.pba_f);
set_cpu_hz(pm_freq_param.cpu_f);
pm_configure_usb_clock();
}
Мы же включили PLL0 и затактировали системные часы от него, разогнав процессор тем самым до 48 МГц:
#define FOSC0 12000000 //!< Osc0 frequency: Hz.
#define OSC0_STARTUP AVR32_PM_OSCCTRL0_STARTUP_2048_RCOSC //!< Osc0 startup time: RCOsc periods.
#define APPLI_CPU_SPEED 24000000
#define APPLI_PBA_SPEED 24000000
volatile avr32_pm_t* pm = &AVR32_PM;
#define EXAMPLE_GCLK_FUNCTION AVR32_PM_GCLK_0_1_FUNCTION
#define EXAMPLE_GCLK_ID 0
#define EXAMPLE_GCLK_PIN AVR32_PM_GCLK_0_1_PIN
void local_start_pll0(volatile avr32_pm_t* pm)
{
pm_switch_to_osc0(pm, FOSC0, OSC0_STARTUP); // Switch main clock to Osc0.
pm_pll_setup(pm,
0, // use PLL0
7, // MUL=7 in the formula
1, // DIV=1 in the formula
0, // Sel Osc0/PLL0 or Osc1/PLL1
16); // lockcount in main clock for the PLL wait lock
pm_pll_set_option(pm, 0, 1, 1, 0);
pm_pll_enable(pm,0);
pm_wait_for_pll0_locked(pm) ;
pm_gc_setup(pm,
EXAMPLE_GCLK_ID,
1, // Use Osc (=0) or PLL (=1), here PLL
0, // Sel Osc0/PLL0 or Osc1/PLL1
0, // disable divisor
0); // no divisor
pm_gc_enable(pm, EXAMPLE_GCLK_ID);
gpio_enable_module_pin(EXAMPLE_GCLK_PIN, EXAMPLE_GCLK_FUNCTION);
pm_cksel(pm, 1, 0, 0, 0, 0, 0);
flashc_set_wait_state(1);
pm_switch_to_clock(pm, AVR32_PM_MCSEL_PLL0);
}
void init(void)
{
local_start_pll0(pm);
}
В результате мы имеем время считывания всех 16 каналов АЦП — 10-15 мкс.
Осциллограф показал еще кое-что интересное — пауза между выдачей контроллером пар сигналов CS и READ составляет примерно 240 нс (на неразогнанном процессоре — все 500).
Завтра планируется работать в этом направлении, т.е. увеличить частоту дрыганья микроконтроллера ногой.
Пока, предварительно, идей две — либо, как посоветовал схемотехник, переводить АЦП с EBI на локальную шину, либо уменьшать время паузы редактированием установочных регистров SMC.