1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

cpu/atxmega: Add external bus interface

Introduce XMEGA EBI driver.  This enable EBI for use with all memory
supported by the device and peripherals. It include support to  SRAM,
SDRAM, LCDs or any other external bus access.

Note: This feature only works for A1/A1U series, which are, the series
with EBI hardware.

Signed-off-by: Gerson Fernando Budke <nandojve@gmail.com>
This commit is contained in:
Gerson Fernando Budke 2021-01-23 18:19:29 -03:00 committed by Gerson Fernando Budke
parent 16f7c94875
commit 307e8c7a17
12 changed files with 820 additions and 4 deletions

View File

@ -130,6 +130,18 @@ static const spi_conf_t spi_config[] = {
#define SPI_NUMOF ARRAY_SIZE(spi_config)
/** @} */
/**
* @name EBI configuration
*
* For more information, see ebi_conf_t structure.
*
* @{
*/
static const ebi_conf_t ebi_config = {
0
};
/** @} */
#ifdef __cplusplus
}
#endif

View File

@ -26,6 +26,7 @@ config CPU_COMMON_ATXMEGA
config CPU_CORE_ATXMEGA_A1
bool
select CPU_COMMON_ATXMEGA
select HAS_ATXMEGA_EBI
config CPU_CORE_ATXMEGA_A3
bool
@ -76,6 +77,11 @@ source "$(RIOTCPU)/atxmega/Kconfig.XMEGAE"
config HAS_CPU_ATXMEGA
bool
config HAS_ATXMEGA_EBI
bool
help
Indicates that the External Bus Interface is present.
config HAS_PERIPH_NVM
bool
help

View File

@ -4,4 +4,8 @@ MODULE = cpu
# add a list of subdirectories, that should also be build
DIRS = periph $(RIOTCPU)/avr8_common/
ifneq (,$(findstring a1,$(shell echo $(CPU_MODEL) | cut -c8-)))
DIRS += ebi
endif
include $(RIOTBASE)/Makefile.base

View File

@ -8,4 +8,8 @@ ifeq (,$(filter cpuid,$(USEMODULE)))
USEMODULE += periph_nvm
endif
ifneq (,$(findstring a1,$(shell echo $(CPU_MODEL) | cut -c8-)))
USEMODULE += atxmega_ebi
endif
include $(RIOTCPU)/avr8_common/Makefile.dep

View File

@ -3,6 +3,10 @@ include $(RIOTCPU)/avr8_common/Makefile.features
# common feature are defined in avr8_common/Makefile.features
# Only add Additional features
ifneq (,$(findstring a1,$(shell echo $(CPU_MODEL) | cut -c8-)))
FEATURES_PROVIDED += atxmega_ebi
endif
FEATURES_PROVIDED += cpu_core_atxmega
FEATURES_PROVIDED += periph_cpuid
FEATURES_PROVIDED += periph_gpio periph_gpio_irq

View File

@ -1,5 +1,8 @@
export CPU_ATXMEGA 1
# should expand RAM ?
EXP_RAM = 0
# CPU ROM/RAM
ifneq (,$(findstring atxmega8,$(CPU_MODEL)))
RAM_LEN = 1K
@ -14,13 +17,13 @@ ifneq (,$(findstring atxmega32,$(CPU_MODEL)))
ROM_LEN = 32K
endif
ifneq (,$(findstring atxmega64,$(CPU_MODEL)))
RAM_LEN ?= 4K
RAM_LEN = 4K
ROM_LEN = 64K
endif
#ifneq (,$(findstring atxmega128,$(CPU_MODEL)))
RAM_LEN ?= 8K
ifneq (,$(findstring atxmega128,$(CPU_MODEL)))
RAM_LEN = 8K
ROM_LEN = 128K
#endif
endif
ifneq (,$(findstring atxmega192,$(CPU_MODEL)))
RAM_LEN = 16K
ROM_LEN = 192K
@ -34,5 +37,14 @@ ifneq (,$(findstring atxmega384,$(CPU_MODEL)))
ROM_LEN = 384K
endif
ifneq (,$(findstring a1,$(shell echo $(CPU_MODEL) | cut -c8-)))
ifeq ($(EXP_RAM),1)
CFLAGS += -DRAM_LEN=$(RAM_LEN)-1
LDSCRIPT_EXTRA = -Wl,--defsym=__heap_end=0x800000+$(RAM_LEN)-1
endif
endif
# CPU depends on the avr8 common module, so include it
include $(RIOTCPU)/avr8_common/Makefile.include
PSEUDOMODULE += atxmega_ebi

4
cpu/atxmega/ebi/Makefile Normal file
View File

@ -0,0 +1,4 @@
# define the module that is build
MODULE = atxmega_ebi
include $(RIOTBASE)/Makefile.base

375
cpu/atxmega/ebi/ebi.c Normal file
View File

@ -0,0 +1,375 @@
/*
* Copyright (C) 2021 Gerson Fernando Budke <nandojve@gmail.com>
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup cpu_atxmega
* @ingroup cpu_atxmega_periph
* @{
*
* @file
* @brief Low-level EBI (External BUS Interface) driver implementation
*
* @author Gerson Fernando Budke <nandojve@gmail.com>
* https://www.avrfreaks.net/forum/xmega-ebi-and-sram
* https://www.avrfreaks.net/forum/xmega-au-four-port-ebi
* https://community.atmel.com/forum/location-variable-specified-address
* @}
*/
#include <avr/io.h>
#include "assert.h"
#include "periph_conf.h"
#include "cpu_pm.h"
#include "cpu_ebi.h"
#define ENABLE_DEBUG 0
#include "debug.h"
void ebi_init(void) __attribute__((naked, section(".init1"), used));
/**
* @brief Set up the I/O ports for use by the EBI.
*
* @note In SDRAM mode the \a sram_ale and \a lpc_ale parameters are ignored
* by the hardware.
*/
void ebi_init(void)
{
EBI_CS_t *cs;
uint8_t mode;
uint8_t sd_ctrl = 0;
uint8_t i;
uint8_t expand_sram = 0;
/*
* This is a mandatory configuration. Whowever, to complete disable module
* just configure it as:
*
* static const ebi_conf_t ebi_config = { 0 };
*
* or, for a temporary disable, set addr_bits to 0 at periph_conf.h:
*
* .addr_bits = 0,
*/
if (ebi_config.addr_bits == 0) {
return;
}
/*
* Set address and control lines as outputs, and active-low control lines
* initially high.
*/
if (ebi_config.flags & EBI_PORT_SDRAM) {
/* With SDRAM, the configuration is fairly fixed. */
PORTH.OUT = 0x0f;
PORTH.DIR = 0xff;
PORTJ.DIR = 0xf0;
PORTK.DIR = 0xff;
} else {
uint8_t ale_mask = ebi_config.sram_ale | ebi_config.lpc_ale;
uint8_t port_mask;
/*
* Set PORTH initial state, set WE and CAS/RE high by default.
* Set chip selects high by default if enabled.
*/
port_mask = 0x03;
if (ebi_config.flags & EBI_PORT_CS0) {
port_mask |= 0x10;
}
if (ebi_config.flags & EBI_PORT_CS1) {
port_mask |= 0x20;
}
if (ebi_config.flags & EBI_PORT_CS2) {
port_mask |= 0x40;
}
if (ebi_config.flags & EBI_PORT_CS3) {
port_mask |= 0x80;
}
PORTH.OUT = port_mask;
/*
* Set PORTH direction, enable WE, CAS/RE and RAS/ALE1 to
* output by default. Set chip select direction if enabled.
*/
port_mask = 0x07;
/* If two latches are in use, enable the ALE2 pin as well. */
if (ale_mask & 0x02) {
port_mask |= 0x08;
}
if (ebi_config.flags & EBI_PORT_CS0 || ebi_config.addr_bits > 16) {
port_mask |= 0x10;
}
if (ebi_config.flags & EBI_PORT_CS1 || ebi_config.addr_bits > 17) {
port_mask |= 0x20;
}
if (ebi_config.flags & EBI_PORT_CS2 || ebi_config.addr_bits > 18) {
port_mask |= 0x40;
}
if (ebi_config.flags & EBI_PORT_CS3 || ebi_config.addr_bits > 19) {
port_mask |= 0x80;
}
PORTH.DIR = port_mask;
/*
* PORTJ is always used for data, direction and value is controlled by
* the EBI module.
*/
/* PORTK is only used in 3-port mode */
if (ebi_config.flags & EBI_PORT_3PORT) {
port_mask = 0x00;
if (ebi_config.flags & EBI_PORT_SRAM) {
/*
* Bits 0..7 go here, so if we have 8 lines or more, enable all
* lines. Otherwise, enable as many as we need.
*/
if (ebi_config.addr_bits < 8) {
port_mask = (1 << ebi_config.addr_bits) - 1;
}
else {
port_mask = 0xff;
}
}
else {
/*
* Bits 8..15 go here, so if we have less than 16 address lines,
* disable the ones that we don't need. If we have 8 lines or
* less, disable all address lines on this port.
*/
if (ebi_config.addr_bits <= 8) {
port_mask = 0x00;
}
else if (ebi_config.addr_bits < 16) {
port_mask = (1 << (ebi_config.addr_bits - 8)) - 1;
}
else {
port_mask = 0xff;
}
}
PORTK.DIR = port_mask;
}
}
if (ebi_config.flags & EBI_PORT_3PORT) {
mode = EBI_IFMODE_3PORT_gc;
}
else {
mode = EBI_IFMODE_2PORT_gc;
}
if (ebi_config.sram_ale == 1) {
mode |= EBI_SRMODE_ALE1_gc;
}
else if (ebi_config.sram_ale == 2) {
mode |= EBI_SRMODE_ALE12_gc;
}
else {
mode |= EBI_SRMODE_NOALE_gc;
}
if (ebi_config.lpc_ale > 0) {
mode |= (ebi_config.lpc_ale << EBI_LPCMODE_gp);
}
if (ebi_config.sdram.cas_latency == EBI_SDRAM_CAS_LAT_3CLK) {
sd_ctrl |= EBI_SDCAS_bm;
}
if (ebi_config.sdram.row_bits == EBI_SDRAM_ROW_BITS_12) {
sd_ctrl |= EBI_SDROW_bm;
}
/* Enable EBI periph clock */
PR.PRGEN &= ~PR_EBI_bm;
/* 8-bit SDRAM requires 4-port EBI, which we don't have. */
EBI.CTRL = EBI_SDDATAW_4BIT_gc
| mode;
EBI.SDRAMCTRLA = sd_ctrl
| ebi_config.sdram.column_bits;
EBI.SDRAMCTRLB = ebi_config.sdram.ld_mode_dly
| ebi_config.sdram.row_cycle_dly
| ebi_config.sdram.row_prechage_dly;
EBI.SDRAMCTRLC = ebi_config.sdram.write_recovery_dly
| ebi_config.sdram.exit_self_rfsh_dly
| ebi_config.sdram.row_to_column_dly;
EBI.REFRESH = ebi_config.sdram.refresh_period & 0x0FFF;
EBI.INITDLY = ebi_config.sdram.init_dly & 0x3FFF;
/* IRQ are disabled here */
cs = (EBI_CS_t *)&EBI.CS0;
for (i = 0; i < PERIPH_EBI_MAX_CS; i++) {
if (ebi_config.cs[i].mode != EBI_CS_MODE_DISABLED_gc &&
ebi_config.cs[i].mode != EBI_CS_MODE_SDRAM_gc) {
/* Configure */
cs[i].CTRLA = ebi_config.cs[i].space;
cs[i].CTRLB = ebi_config.cs[i].wait;
cs[i].BASEADDR = ((ebi_config.cs[i].address >> 8) & 0xfff0);
/* Enable */
cs[i].CTRLA = ebi_config.cs[i].space | ebi_config.cs[i].mode;
if (ebi_config.cs[i].address == 0) {
expand_sram = 1;
}
}
}
/**
* Only CS[3] can be configured as SDRAM.
* CS structure is little bit different too.
*/
if (ebi_config.cs[3].mode == EBI_CS_MODE_SDRAM_gc) {
cs[3].CTRLA = ebi_config.cs[3].space;
cs[3].CTRLB = ebi_config.sdram.mode
| (ebi_config.sdram.refresh ? EBI_CS_SDSREN_bm : 0);
cs[3].BASEADDR = ((ebi_config.cs[3].address >> 8) & 0xfff0);
cs[3].CTRLA = ebi_config.cs[3].space | ebi_config.cs[3].mode;
if (ebi_config.cs[3].address == 0) {
expand_sram = 1;
}
while (!(cs[3].CTRLB & EBI_CS_SDINITDONE_bm)) {};
}
if (expand_sram > 0) {
/**
* @brief Set new Stack Pointer
*/
__asm__ volatile (
"out __SP_L__, %A[stack] \n\t"
"out __SP_H__, %B[stack] \n\t"
: /* no output */
: [stack] "r"(RAM_LEN)
: "memory"
);
};
}
uint16_t hugemem_read16(const hugemem_ptr_t from)
{
uint16_t value;
__asm__ volatile (
"movw r30, %A[from] \n\t"
"out %[rampz], %C[from] \n\t"
"ld %A[dest], Z+ \n\t"
"ld %B[dest], Z \n\t"
"out %[rampz], __zero_reg__ \n\t"
: [dest] "=r"(value)
: [from] "r"(from),
[rampz] "i"(&RAMPZ)
: "r30", "r31"
);
return value;
}
void hugemem_write16(hugemem_ptr_t to, uint16_t val)
{
__asm__ volatile (
"movw r30, %A[to] \n\t"
"out %[rampz], %C[to] \n\t"
"st Z+, %A[val] \n\t"
"st Z, %B[val] \n\t"
"out %[rampz], __zero_reg__ \n\t"
: /* no output */
: [to] "r"(to),
[val] "r"(val),
[rampz] "i"(&RAMPZ)
: "r30", "r31"
);
}
uint32_t hugemem_read32(const hugemem_ptr_t from)
{
uint32_t value;
__asm__ volatile (
"movw r30, %A[from] \n\t"
"out %[rampz], %C[from] \n\t"
"ld %A[dest], Z+ \n\t"
"ld %B[dest], Z+ \n\t"
"ld %C[dest], Z+ \n\t"
"ld %D[dest], Z \n\t"
"out %[rampz], __zero_reg__ \n\t"
: [dest] "=r"(value)
: [from] "r"(from),
[rampz] "i"(&RAMPZ)
: "r30", "r31"
);
return value;
}
void hugemem_write32(hugemem_ptr_t to, uint32_t val)
{
__asm__ volatile (
"movw r30, %A[to] \n\t"
"out %[rampz], %C[to] \n\t"
"st Z+, %A[val] \n\t"
"st Z+, %B[val] \n\t"
"st Z+, %C[val] \n\t"
"st Z, %D[val] \n\t"
"out %[rampz], __zero_reg__ \n\t"
: /* no output */
: [to] "r"(to),
[val] "r"(val),
[rampz] "i"(&RAMPZ)
: "r30", "r31"
);
}
void hugemem_read_block(void *to, const hugemem_ptr_t from, size_t size)
{
if (size > 0) {
__asm__ volatile (
"movw r30, %A[from] \n\t"
"out %[rampz], %C[from] \n\t"
"get_%=: \n\t"
"ld __tmp_reg__, Z+ \n\t"
"st X+, __tmp_reg__ \n\t"
"sbiw %A[size], 1 \n\t"
"brne get_%= \n\t"
"out %[rampz], __zero_reg__ \n\t"
: [to] "+x"(to),
[size] "+w"(size)
: [from] "r"(from),
[rampz] "i"(&RAMPZ)
: "r30", "r31"
);
}
}
void hugemem_write_block(hugemem_ptr_t to, const void *from, size_t size)
{
if (size > 0) {
__asm__ volatile (
"movw r30, %A[from] \n\t"
"out %[rampz], %C[from] \n\t"
"put_%=: \n\t"
"ld __tmp_reg__, X+ \n\t"
"st Z+, __tmp_reg__ \n\t"
"sbiw %A[size], 1 \n\t"
"brne put_%= \n\t"
"out %[rampz], __zero_reg__ \n\t"
: [from] "+x"(from),
[size] "+w"(size)
: [to] "r"(to),
[rampz] "i"(&RAMPZ)
: "r30", "r31"
);
}
}

View File

@ -0,0 +1,154 @@
/*
* Copyright (C) 2021 Gerson Fernando Budke
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup cpu_atxmega
* @{
*
* @file
* @brief External Bus Interface API
*
* @author Gerson Fernando Budke <nandojve@gmail.com>
*/
#include "periph_cpu.h"
#ifndef CPU_EBI_H
#define CPU_EBI_H
#ifdef __cplusplus
extern "C" {
#endif
typedef uint32_t hugemem_ptr_t;
#define HUGEMEM_NULL 0
void ebi_init(void);
/**
* @brief Load byte register from external memory pointer
*
* @param from 24-bit external memory address
* @return uint8_t 8-bit value
*/
static inline uint8_t hugemem_read8(const hugemem_ptr_t from)
{
uint8_t value;
__asm__ volatile (
/* place 24 bit address into r30, r31, RAMPZ
* r31:r30 <- %B[from]:%A[from]
* RAMPZ <- %C[from]
*/
"movw r30, %A[from] \n\t"
"out %[rampz], %C[from] \n\t"
/* read byte from 24 bit address
* register <- *(RAMPZ + Z)
*/
"ld %[dest], Z \n\t"
/* clear ramp */
"out %[rampz], __zero_reg__ \n\t"
: [dest] "=r"(value)
: [from] "r"(from),
[rampz] "i"(&RAMPZ)
: "r30", "r31"
);
return value;
}
/**
* @brief Store byte register to external memory pointer
*
* @param to 24-bit external memory address
* @param val 8-bit value
*/
static inline void hugemem_write8(hugemem_ptr_t to, uint8_t val)
{
__asm__ volatile (
/* place 24 bit address into r30, r31, RAMPZ
* r31:r30 <- %B[from]:%A[from]
* RAMPZ <- %C[from]
*/
"movw r30, %A[to] \n\t"
"out %[rampz], %C[to] \n\t"
/* write byte to 24 bit address
* (RAMPZ + Z) <- register
*/
"st Z, %[val] \n\t"
/* clear ramp */
"out %[rampz], __zero_reg__ \n\t"
:
: [to] "r"(to),
[val] "r"(val),
[rampz] "i"(&RAMPZ)
: "r30", "r31"
);
}
/**
* @brief Load register pair from external memory pointer
*
* @param from 24-bit external memory address
* @return uint16_t 8-bit value
*/
uint16_t hugemem_read16(const hugemem_ptr_t from);
/**
* @brief Store register pair to external memory pointer
*
* @param to 24-bit external memory address
* @param val 16-bit value
*/
void hugemem_write16(hugemem_ptr_t to, uint16_t val);
/**
* @brief Load two register pair from external memory pointer
*
* @param from 24-bit external memory address
* @return uint8_t 32-bit value
*/
uint32_t hugemem_read32(const hugemem_ptr_t from);
/**
* @brief Store two register pair to external memory pointer
*
* @param to 24-bit external memory address
* @param val 32-bit value
*/
void hugemem_write32(hugemem_ptr_t to, uint32_t val);
/**
* @brief Read byte stream from external memory to internal memory
*
* @param to intenal memory pointer
* @param from 24-bit external memory pointer
* @param size number of bytes to read
*
* @note The address range to copy from is within 64 kB boundary
*/
void hugemem_read_block(void *to, const hugemem_ptr_t from, size_t size);
/**
* @brief Write byte stream from internal memory to external memory
*
* @param to 24-bit external memory pointer
* @param from intenal memory pointer
* @param size number of bytes to write
*
* @note The address range to copy to is within 64 kB boundary
*/
void hugemem_write_block(hugemem_ptr_t to, const void *from, size_t size);
#ifdef __cplusplus
}
#endif
#endif /* CPU_EBI_H */
/** @} */

View File

@ -354,6 +354,236 @@ typedef enum {
} spi_clk_t;
/** @} */
#if defined(__AVR_ATxmega64A1__) || \
defined(__AVR_ATxmega128A1__) || \
defined(__AVR_ATxmega64A1U__) || \
defined(__AVR_ATxmega128A1U__) || \
defined(Doxygen)
/**
* @brief EBI (External Bus Interface)
* {@
*/
/**
* @brief EBI Low Pin Count (LPC) Mode Address Latch Enable (ALE) config
*/
typedef enum {
EBI_LPC_MODE_ALE1 = 0x01, /**< Data multiplexed with Address byte 0 */
EBI_LPC_MODE_ALE12 = 0x03, /**< Data multiplexed with Address byte 0 and 1 */
} ebi_lpc_mode_t;
/**
* @brief EBI Port Access Flags
*
* Indicate what should be configured
*/
typedef enum {
EBI_PORT_3PORT = 0x01, /**< Three Port Config */
EBI_PORT_SDRAM = 0x02, /**< SDRAM Port Config */
EBI_PORT_SRAM = 0x04, /**< SRAM Port Config */
EBI_PORT_LPC = 0x08, /**< Low Pin Count Port Config */
EBI_PORT_CS0 = 0x10, /**< Chip Select 0 Config */
EBI_PORT_CS1 = 0x20, /**< Chip Select 1 Config */
EBI_PORT_CS2 = 0x40, /**< Chip Select 2 Config */
EBI_PORT_CS3 = 0x80, /**< Chip Select 3 Config */
EBI_PORT_CS_ALL = 0xF0, /**< Chip Select 0-3 Config */
} ebi_port_mask_t;
/**
* @brief SDRAM Column Address Strobe latency
*/
typedef enum {
EBI_SDRAM_CAS_LAT_2CLK = 0x00, /**< 2 Clk PER2 cycles delay */
EBI_SDRAM_CAS_LAT_3CLK = 0x01, /**< 3 Clk PER2 cycles delay */
} ebi_sdram_cas_latency_t;
/**
* @brief SDRAM number of Row Bits
*/
typedef enum {
EBI_SDRAM_ROW_BITS_11 = 0x00, /**< 11 row bits */
EBI_SDRAM_ROW_BITS_12 = 0x01, /**< 12 row bits */
} ebi_sdram_row_bits_t;
/**
* @brief EBI maximum Chip Select
*/
#define PERIPH_EBI_MAX_CS (4)
/**
* @brief EBI SDRAM Chip Select
*/
#define PERIPH_EBI_SDRAM_CS (3)
/**
* @brief EBI Chip Select configuration structure
*/
typedef struct {
EBI_CS_MODE_t mode; /**< Chip Select address mode */
#if defined (__AVR_ATxmega64A1U__) || defined (__AVR_ATxmega128A1U__)
EBI_CS_ASPACE_t space; /**< Chip Select address space */
#else
EBI_CS_ASIZE_t space; /**< Chip Select address space */
#endif
EBI_CS_SRWS_t wait; /**< SRAM Wait State Selection */
uint32_t address; /**< Chip Select Base Address */
} ebi_cs_t;
/**
* @brief EBI SDRAM configuration structure
*/
typedef struct {
uint8_t refresh; /**< Self-Refresh Enabled */
uint16_t refresh_period; /**< microseconds */
uint16_t init_dly; /**< microseconds */
EBI_CS_SDMODE_t mode; /**< Access Mode */
ebi_sdram_cas_latency_t cas_latency; /**< CAS Latency */
ebi_sdram_row_bits_t row_bits; /**< ROW bits */
EBI_SDCOL_t column_bits; /**< COLUMN bits */
EBI_MRDLY_t ld_mode_dly; /**< Number of Clk PER2 cycles */
EBI_ROWCYCDLY_t row_cycle_dly; /**< Number of Clk PER2 cycles */
EBI_RPDLY_t row_prechage_dly; /**< Number of Clk PER2 cycles */
EBI_WRDLY_t write_recovery_dly; /**< Number of Clk PER2 cycles */
EBI_ESRDLY_t exit_self_rfsh_dly; /**< Number of Clk PER2 cycles */
EBI_ROWCOLDLY_t row_to_column_dly; /**< Number of Clk PER2 cycles */
} ebi_sd_t;
/**
* @brief EBI configuration structure
*
* The ebi_conf_t define the whole external memory that ATxmega A1 can address.
* It is recommended read all EBI chapter from XMEGA-AU manual.
*
* The external address space can be used to address external peripherals and
* expand SRAM. The ebi driver provide methods to read/write in external
* address space. The SRAM can be expanded up to 64k when one chip select
* address have value equal to zero. To allow expand external RAM both
* @b RAM_LEN and @b EXP_RAM variables should be override at board
* makefile.include file.
*
* When expanding RAM for use with RIOT-OS, the memory address must be aligned
* at external memory size boundary, respecting power of 2. In this case, to
* add 32K memory on the system, the chip select address should be set to 0,
* or 32k, or 64 etc. This means that when the board have external memory and
* user wants to map part of that memory to expand RAM, both internal and
* external memories must have same start address @b A, inclusive, see image
* for details. This is necessary to make sure RIOT-OS have a contiguous address
* space. The drawback is that first @b Xk external memory will be lost.
* Assuming internal top address memory is @b B and external top address memory
* is @b C. The XMEGA will automatically access internal memory <b><= B</b>
* when address collide with external memory. At address <b>>= B + 1</b>, XMEGA
* will access memory thru EBI. Also, note that @b RAM_LEN must be a power
* of 2, so it can't e.g. be 48k.
*
* C ------
* | |
* | |
* | |
* B -----| |
* | | |
* | | |
* A -----------
*
* @note To avoid parser problems, @b RAM_LEN must be defined as decimal value.
*
* Example: Add 256K of external RAM
*
* The max addressable RAM by SP is 64K due to limit of 16 bits. In this case,
* RAM will be 64K. The remaining RAM can be addressed only by ebi_mem methods
* and GCC doesn't see it.
*
* At board/periph_conf.h:
*
* static const ebi_conf_t ebi_config = {
* ...
* .cs = {
* { EBI_CS_MODE_DISABLED_gc,
* 0,
* EBI_CS_SRWS_0CLK_gc,
* 0x0UL,
* },
* { EBI_CS_MODE_DISABLED_gc,
* 0,
* EBI_CS_SRWS_0CLK_gc,
* 0x0UL,
* },
* { EBI_CS_MODE_LPC_gc,
* EBI_CS_ASPACE_256KB_gc,
* EBI_CS_SRWS_1CLK_gc,
* 0x0UL,
* },
* { EBI_CS_MODE_DISABLED_gc,
* 0,
* EBI_CS_SRWS_0CLK_gc,
* 0x0UL,
* },
* },
* };
*
* At board/Makefile.include:
* override RAM_LEN = 65536
* override EXP_RAM = 1
*
* Example: Add 32K of external RAM and a LCD
*
* At board/periph_conf.h:
*
* static const ebi_conf_t ebi_config = {
* ...
* .cs = {
* { EBI_CS_MODE_DISABLED_gc,
* 0,
* EBI_CS_SRWS_0CLK_gc,
* 0x0UL,
* },
* { EBI_CS_MODE_DISABLED_gc,
* 0,
* EBI_CS_SRWS_0CLK_gc,
* 0x0UL,
* },
* { EBI_CS_MODE_LPC_gc,
* EBI_CS_ASPACE_32KB_gc,
* EBI_CS_SRWS_1CLK_gc,
* 0x0UL,
* },
* { EBI_CS_MODE_LPC_gc,
* EBI_CS_ASPACE_256B_gc,
* EBI_CS_SRWS_5CLK_gc,
* 0x100000UL,
* },
* },
* };
*
* At board/Makefile.include:
* override RAM_LEN = 32768
* override EXP_RAM = 1
*
* This data structure a mandatory configuration for A1 variation. If no
* external memory is used the module can be disabled defining data struct
* with all zeros, as below:
*
* static const ebi_conf_t ebi_config = { 0 };
*
* or, for a temporary disable, set addr_bits to 0 at periph_conf.h:
*
* static const ebi_conf_t ebi_config = {
* .addr_bits = 0,
* ...
* };
*
*/
typedef struct {
uint8_t addr_bits; /**< EBI port address lines */
ebi_port_mask_t flags; /**< EBI port flags */
uint8_t sram_ale; /**< Number of ALE for SRAM mode */
uint8_t lpc_ale; /**< Number of ALE for LPC mode */
ebi_sd_t sdram; /**< SDRAM configuration */
ebi_cs_t cs[PERIPH_EBI_MAX_CS]; /**< Chip Select configuration */
} ebi_conf_t;
/** @} */
#endif /* __AVR_ATxmegaxxxA1x__ */
#ifdef __cplusplus
}
#endif

View File

@ -135,4 +135,14 @@ void pm_periph_power_off(void)
for (i = 0; i <= 7; i++) {
reg[i] = 0xff;
}
/* EBI Must be always enabled when configured */
#if defined (__AVR_ATxmega64A1__) || \
defined (__AVR_ATxmega64A1U__) || \
defined (__AVR_ATxmega128A1__) || \
defined (__AVR_ATxmega128A1U__)
if (ebi_config.addr_bits > 0) {
reg[0] &= ~PR_EBI_bm;
}
#endif
}

View File

@ -27,6 +27,7 @@ $(if $(ROM_LEN),,$(error ROM_LEN is not defined))
$(if $(RAM_LEN),,$(error RAM_LEN is not defined))
LINKFLAGS += $(LINKFLAGPREFIX)--defsym=__TEXT_REGION_LENGTH__=$(ROM_LEN)$(if $(ROM_RESERVED),-$(ROM_RESERVED))
LINKFLAGS += $(LINKFLAGPREFIX)--defsym=__DATA_REGION_LENGTH__=$(RAM_LEN)
LINKFLAGS += $(LDSCRIPT_EXTRA)
ifeq ($(LTO),1)
# avr-gcc <4.8.3 has a bug when using LTO which causes a warning to be printed always: