NetBurner 3.5.7
PDF Version
semc_utils.h
1
14#ifndef SEMC_UTILS_H
15#define SEMC_UTILS_H
16
17#include <semc.h>
18#include <stdint.h>
19
20// ============================================================================
21// TIMING CALCULATION MACROS
22// ============================================================================
23
31#define NS_TO_CYCLES_CLK(ns, clk_mhz) (((ns) * (clk_mhz) + 999) / 1000)
32
39#define CYCLES_TO_N_PLUS_1_VAL(cycles) ((cycles) > 0 ? (cycles) - 1 : 0)
40
48#define PS_TO_CYCLES(ps, clk_mhz) (((ps) * (clk_mhz) + 999999) / 1000000)
49
57#define CYCLES_TO_NS(cycles, clk_mhz) (((cycles) * 1000) / (clk_mhz))
58
67#define TIMING_OK(configured_cycles, required_ns, clk_mhz) \
68 (CYCLES_TO_NS(configured_cycles, clk_mhz) >= (required_ns))
69
70// ============================================================================
71// CONFIGURATION VALIDATION MACROS
72// ============================================================================
73
81#define IS_ALIGNED(addr, size) (((addr) & ((size) - 1)) == 0)
82
89#define IS_POWER_OF_2(size) (((size) != 0) && (((size) & ((size) - 1)) == 0))
90
97#define IS_SEMC_ADDR(addr) ((addr) >= 0x80000000 && (addr) < 0xA0000000)
98
99// ============================================================================
100// COMMON SRAM DEVICE TIMING PRESETS
101// ============================================================================
102
122
128static const SRAM_Timing_Spec_t SRAM_10NS = {
130 .chip_enable_access_ns = 10,
131 .output_enable_access_ns = 5,
132 .write_cycle_time_ns = 10,
133 .read_cycle_time_ns = 10,
134 .address_setup_time_ns = 0,
135 .address_hold_time_ns = 3,
136 .chip_select_setup_ns = 0,
137 .write_pulse_width_ns = 8,
138 .output_hold_time_ns = 3
139};
140
146static const SRAM_Timing_Spec_t SRAM_55NS = {
148 .chip_enable_access_ns = 55,
149 .output_enable_access_ns = 25,
150 .write_cycle_time_ns = 55,
151 .read_cycle_time_ns = 55,
152 .address_setup_time_ns = 0,
153 .address_hold_time_ns = 5,
154 .chip_select_setup_ns = 0,
155 .write_pulse_width_ns = 45,
156 .output_hold_time_ns = 5
157};
158
164static const SRAM_Timing_Spec_t SRAM_70NS = {
166 .chip_enable_access_ns = 70,
167 .output_enable_access_ns = 30,
168 .write_cycle_time_ns = 70,
169 .read_cycle_time_ns = 70,
170 .address_setup_time_ns = 0,
171 .address_hold_time_ns = 5,
172 .chip_select_setup_ns = 10,
173 .write_pulse_width_ns = 55,
174 .output_hold_time_ns = 5
175};
176
177// ============================================================================
178// HELPER FUNCTIONS FOR SEMC CONFIGURATION
179// ============================================================================
180
244inline SEMC_cfg_t CreateSEMCConfigFromSpec(
245 const SRAM_Timing_Spec_t &spec,
246 uint32_t clk_mhz,
247 uint8_t bus_width,
248 uint8_t margin_percent,
249 PinIO clk_pin,
250 PinIO cs_pin)
251{
252 SEMC_cfg_t cfg = {};
253
254 // Apply margin to all timing values
255 float margin = 1.0f + (margin_percent / 100.0f);
256
257 // Basic configuration
258 cfg.busWidth = (bus_width == 16) ? SEMC_BusWidth_t::Width_16 : SEMC_BusWidth_t::Width_8;
263 cfg.advPol = false;
264 cfg.advHoldLvl = false;
265
266 // Calculate timing parameters with margin
267 cfg.cs_setup = CYCLES_TO_N_PLUS_1_VAL(
268 NS_TO_CYCLES_CLK(spec.chip_select_setup_ns * margin, clk_mhz)
269 );
270
271 cfg.cs_hold_min = CYCLES_TO_N_PLUS_1_VAL(
272 NS_TO_CYCLES_CLK(10 * margin, clk_mhz) // Minimum 10ns
273 );
274
275 cfg.addr_setup = CYCLES_TO_N_PLUS_1_VAL(
276 NS_TO_CYCLES_CLK(spec.address_setup_time_ns * margin, clk_mhz)
277 );
278
279 cfg.addr_hold = CYCLES_TO_N_PLUS_1_VAL(
280 NS_TO_CYCLES_CLK(spec.address_hold_time_ns * margin, clk_mhz)
281 );
282
283 cfg.wr_en_lo = CYCLES_TO_N_PLUS_1_VAL(
284 NS_TO_CYCLES_CLK(spec.write_pulse_width_ns * margin, clk_mhz)
285 );
286
287 cfg.wr_en_hi = CYCLES_TO_N_PLUS_1_VAL(
288 NS_TO_CYCLES_CLK((spec.write_cycle_time_ns - spec.write_pulse_width_ns) * margin, clk_mhz)
289 );
290
291 cfg.rd_en_lo = CYCLES_TO_N_PLUS_1_VAL(
292 NS_TO_CYCLES_CLK(spec.output_enable_access_ns * margin, clk_mhz)
293 );
294
295 cfg.rd_en_hi = CYCLES_TO_N_PLUS_1_VAL(
296 NS_TO_CYCLES_CLK(spec.address_access_time_ns * margin, clk_mhz)
297 );
298
299 cfg.addr_wr_hold = CYCLES_TO_N_PLUS_1_VAL(
300 NS_TO_CYCLES_CLK(spec.address_hold_time_ns * margin, clk_mhz)
301 );
302
303 cfg.turnaround = 2; // 2 cycle turnaround
304
305 cfg.cs_min_intv = CYCLES_TO_N_PLUS_1_VAL(2);
306
307 // Pin assignments
308 cfg.clkPin = clk_pin;
309 cfg.csPin = cs_pin;
310
311 return cfg;
312}
313
347inline void PrintSEMCConfig(const SEMC_cfg_t &cfg, uint32_t clk_mhz)
348{
349 printf("SEMC Configuration Details:\n");
350 printf("==========================\n");
351
352 // Basic settings
353 printf("Bus Width: %s\n", cfg.busWidth == SEMC_BusWidth_t::Width_16 ? "16-bit" : "8-bit");
354 printf("Clock Mode: %s\n", cfg.clkMode == SEMC_ClkMode_t::Async ? "Async" : "Sync");
355 printf("Mux Mode: ");
356 switch (cfg.muxMode) {
357 case SEMC_AddrMux_t::Mux: printf("Multiplexed\n"); break;
358 case SEMC_AddrMux_t::AdvMux: printf("Advanced Mux\n"); break;
359 case SEMC_AddrMux_t::Bus: printf("Non-multiplexed\n"); break;
360 }
361
362 // Timing parameters
363 printf("\nTiming Parameters (Async Mode):\n");
364 printf(" CS Setup: %u cycles (%u ns)\n",
365 cfg.cs_setup + 1, CYCLES_TO_NS(cfg.cs_setup + 1, clk_mhz));
366 printf(" CS Hold: %u cycles (%u ns)\n",
367 cfg.cs_hold_min + 1, CYCLES_TO_NS(cfg.cs_hold_min + 1, clk_mhz));
368 printf(" Address Setup: %u cycles (%u ns)\n",
369 cfg.addr_setup + 1, CYCLES_TO_NS(cfg.addr_setup + 1, clk_mhz));
370 printf(" Address Hold: %u cycles (%u ns)\n",
371 cfg.addr_hold + 1, CYCLES_TO_NS(cfg.addr_hold + 1, clk_mhz));
372 printf(" Write Enable Low: %u cycles (%u ns)\n",
373 cfg.wr_en_lo + 1, CYCLES_TO_NS(cfg.wr_en_lo + 1, clk_mhz));
374 printf(" Write Enable High: %u cycles (%u ns)\n",
375 cfg.wr_en_hi + 1, CYCLES_TO_NS(cfg.wr_en_hi + 1, clk_mhz));
376 printf(" Read Enable Low: %u cycles (%u ns)\n",
377 cfg.rd_en_lo + 1, CYCLES_TO_NS(cfg.rd_en_lo + 1, clk_mhz));
378 printf(" Read Enable High: %u cycles (%u ns)\n",
379 cfg.rd_en_hi + 1, CYCLES_TO_NS(cfg.rd_en_hi + 1, clk_mhz));
380 printf(" Address Write Hold: %u cycles (%u ns)\n",
381 cfg.addr_wr_hold + 1, CYCLES_TO_NS(cfg.addr_wr_hold + 1, clk_mhz));
382 printf(" Turnaround: %u cycles (%u ns)\n",
383 cfg.turnaround, CYCLES_TO_NS(cfg.turnaround, clk_mhz));
384 printf(" CS Min Interval: %u cycles (%u ns)\n",
385 cfg.cs_min_intv + 1, CYCLES_TO_NS(cfg.cs_min_intv + 1, clk_mhz));
386
387 // Calculated cycle times
388 uint32_t write_cycle = (cfg.wr_en_lo + 1) + (cfg.wr_en_hi + 1);
389 uint32_t read_cycle = (cfg.rd_en_lo + 1) + (cfg.rd_en_hi + 1);
390
391 printf("\nCalculated Timing:\n");
392 printf(" Write Cycle: %u cycles (%u ns)\n",
393 write_cycle, CYCLES_TO_NS(write_cycle, clk_mhz));
394 printf(" Read Cycle: %u cycles (%u ns)\n",
395 read_cycle, CYCLES_TO_NS(read_cycle, clk_mhz));
396 printf("==========================\n\n");
397}
398
431inline bool ValidateSEMCConfig(const SEMC_cfg_t &cfg, uint32_t base_addr, uint32_t size)
432{
433 bool valid = true;
434
435 printf("Validating SEMC Configuration...\n");
436
437 // Check address alignment
438 if (!IS_ALIGNED(base_addr, size)) {
439 printf(" ERROR: Base address 0x%08X not aligned to size 0x%08X\n",
440 base_addr, size);
441 valid = false;
442 }
443
444 // Check size is power of 2
445 if (!IS_POWER_OF_2(size)) {
446 printf(" ERROR: Size 0x%08X is not a power of 2\n", size);
447 valid = false;
448 }
449
450 // Check address range
451 if (!IS_SEMC_ADDR(base_addr)) {
452 printf(" ERROR: Base address 0x%08X not in valid SEMC range (0x80000000-0x9FFFFFFF)\n",
453 base_addr);
454 valid = false;
455 }
456
457 // Check for potential timing issues
458 if (cfg.cs_setup == 0) {
459 printf(" WARNING: CS setup is 0 - consider adding margin\n");
460 }
461
462 if (cfg.rd_en_hi < 3) {
463 printf(" WARNING: Read enable high is very short - may not meet timing\n");
464 }
465
466 if (cfg.wr_en_hi < 3) {
467 printf(" WARNING: Write enable high is very short - may not meet timing\n");
468 }
469
470 if (valid) {
471 printf(" Configuration validation PASSED\n");
472 } else {
473 printf(" Configuration validation FAILED\n");
474 }
475
476 return valid;
477}
478
479#endif // SEMC_UTILS_H
GPIO Pin Class.
Definition coldfire/cpu/MCF5441X/include/cpu_pins.h:15
SEMC_BusWidth_t
Data bus width configuration for SEMC interface.
Definition semc.h:491
@ Async
Asynchronous mode. Timing based on fixed delays. No clock synchronization required....
@ AdvMux
Advanced multiplexed mode. Enhanced multiplexing with additional control signals for complex timing.
@ Bus
Non-multiplexed bus mode (write only). Separate address and data buses. Reads are performed as AD-Mux...
@ Mux
Multiplexed address/data mode. Address and data share the same pins. Requires ADV signal to latch add...
@ Width_8
8-bit data bus (D[7:0]). Suitable for 8-bit memory devices or low pin-count designs.
@ Width_16
16-bit data bus (D[15:0]). Suitable for 16-bit memory devices. Provides 2x throughput compared to 8-b...
@ Burst_1
Single-beat transfer. No burst mode. Each access requires full address cycle. Use for random access o...
@ Width_0
No column addressing. Do not configure address pins for column mode. Use for simple SRAM/NOR Flash wi...
Configuration structure for SEMC (Smart External Memory Controller) interface.
Definition semc.h:796
uint32_t wr_en_lo
Definition semc.h:832
uint32_t addr_wr_hold
Definition semc.h:851
uint32_t cs_min_intv
Definition semc.h:855
SEMC_ColAddrWidth_t colAddrWidth
Definition semc.h:814
uint32_t rd_en_hi
Definition semc.h:835
PinIO clkPin
Definition semc.h:861
SEMC_ClkMode_t clkMode
Definition semc.h:807
uint32_t cs_setup
Definition semc.h:828
SEMC_AddrMux_t muxMode
Definition semc.h:811
uint32_t rd_en_lo
Definition semc.h:834
uint32_t wr_en_hi
Definition semc.h:833
bool advPol
Definition semc.h:812
uint32_t turnaround
Definition semc.h:852
bool advHoldLvl
Definition semc.h:813
uint32_t cs_hold_min
Definition semc.h:829
PinIO csPin
Definition semc.h:862
uint32_t addr_hold
Definition semc.h:831
SEMC_Burst_t burstLen
Definition semc.h:809
SEMC_BusWidth_t busWidth
Definition semc.h:806
uint32_t addr_setup
Definition semc.h:830
Timing specifications for common SRAM speeds.
Definition semc_utils.h:110
uint32_t chip_enable_access_ns
tACE - CE to data valid
Definition semc_utils.h:112
uint32_t output_enable_access_ns
tOE - OE to data valid
Definition semc_utils.h:113
uint32_t read_cycle_time_ns
tRC - Read cycle time
Definition semc_utils.h:115
uint32_t address_hold_time_ns
tAH - Address hold from WE
Definition semc_utils.h:117
uint32_t chip_select_setup_ns
tCS - CS setup time
Definition semc_utils.h:118
uint32_t address_access_time_ns
tAA - Address to data valid
Definition semc_utils.h:111
uint32_t address_setup_time_ns
tAS - Address setup to WE
Definition semc_utils.h:116
uint32_t write_pulse_width_ns
tWP - WE pulse width
Definition semc_utils.h:119
uint32_t output_hold_time_ns
tOH - Data hold after OE high
Definition semc_utils.h:120
uint32_t write_cycle_time_ns
tWC - Write cycle time
Definition semc_utils.h:114