mirror of
https://github.com/elua/elua.git
synced 2025-01-08 20:56:17 +08:00
259 lines
12 KiB
Plaintext
259 lines
12 KiB
Plaintext
(NOTE: view this file with a monospaced font)
|
|
|
|
eLua platform interface
|
|
================================================================================
|
|
|
|
This document describes the "platform" interface in eLua. Its purpose is to ease
|
|
the task of porting eLua to a new platform, as well as having a uniform layer
|
|
for accesing peripherals (such as PIO, UART, SPI ...) on all platforms.
|
|
|
|
The definitions of the functions shown here are in the "inc/platform.h" file.
|
|
Some of the functions are required, others are optional; see also the "adding
|
|
a new platform.txt" and "platform modules.txt" files for additional information.
|
|
Also, for each function or function group, the name of the module(s) that use
|
|
it (if any) is specified. If other part of the code uses the module, a
|
|
"ALSO USED BY" line will be present in the module description.
|
|
|
|
================================================================================
|
|
|
|
int platform_init();
|
|
|
|
TYPE: REQUIRED
|
|
USED BY MODULE: N/A
|
|
|
|
PURPOSE: platform-specific initialization (this is a good place to initialize
|
|
the platform CPU, as well as the CPU peripherals, like the UART).
|
|
RETURNS: PLATFORM_OK or PLATFORM_ERR (if PLATFORM_ERR is returned the program
|
|
blocks in an infinite loop).
|
|
|
|
================================================================================
|
|
|
|
void* platform_get_first_free_ram( unsigned id );
|
|
void* platform_get_last_free_ram( unsigned id );
|
|
|
|
TYPE: REQUIRED
|
|
USED BY MODULE: N/A
|
|
|
|
PURPOSE: returns the first and the last free RAM address; the space between them
|
|
will be used for the system heap. 'id' is a memory space identifier. This can be
|
|
used if there is more than one RAM memory available in the system, and their
|
|
address ranges do not overlap. For example, one can have a CPU with internal RAM
|
|
(a very common case) but also an external RAM chip. In this case there are two
|
|
memory spaces, the first one being the internal RAM and the other one the
|
|
external RAM. While each of them in part is contiguous, they are generally not
|
|
contigous to each other in the system address space, so they must be treated as
|
|
two separate address spaces. If the multiple allocator (see building.txt) is
|
|
used you can define as many memory spaces as you wish in your system, the
|
|
allocator will make sure to use all of them.
|
|
If the system RAM exists in a single memory space (for example the internal RAM
|
|
on the MCU) the CPU's stack pointer should be set at the end of the RAM at
|
|
startup. Thus, the first free ram will start right after the data/bss sections,
|
|
and the last free RAM is the last physical address of RAM minus the size of the
|
|
stack. The heap and the stack will grow on opposite directions (upward/downward)
|
|
and the heap will stop if asked to grow "over" the stack.
|
|
If the MCU has both internal RAM and external RAM, a simple arrangement is to
|
|
place the CPU stack at the end of the internal RAM and the heap in the external
|
|
memory (which is generally much larger than the MCU's internal memory). Another
|
|
arrangement is to use the multiple allocator and the memory space id as
|
|
described above.
|
|
|
|
================================================================================
|
|
|
|
int platform_pio_has_port( unsigned port );
|
|
const char* platform_pio_get_prefix( unsigned port );
|
|
int platform_pio_has_pin( unsigned port, unsigned pin );
|
|
pio_type platform_pio_op( unsigned port, pio_type pinmask, int op );
|
|
|
|
TYPE: OPTIONAL
|
|
USED BY MODULE: pio
|
|
|
|
PURPOSE: PIO operations. eLua defines a number of "virtual ports", each one 32
|
|
bits in size, as shows in "inc/platform.h". But since it somehow needs to map
|
|
these virtual ports to physical ports, it will ask the platform if a port is
|
|
physically present (via platform_pio_has_port) and also if a bit (a "pin") in
|
|
the port is physically present (via platform_pio_has_pin).
|
|
platform_pio_get_prefix gets a port number and return the "port name" as defined
|
|
in the device datasheet. Some devices use PA0, PA1, others simply P0, P1. This
|
|
is what this function is expected to return.
|
|
The platform_pio_op function is the one that does the actual work with the PIO
|
|
subsystem. It receives an operation id ("op") as well as a mask ("pinmask") to
|
|
which the operation applies. The possible operations are shown in the 'enum'
|
|
below (taken from "inc/platform.h"):
|
|
|
|
(BEGIN inc/platform.h)
|
|
enum
|
|
{
|
|
// Pin operations
|
|
PLATFORM_IO_PIN_SET, // Set pin(s) to 1
|
|
PLATFORM_IO_PIN_CLEAR, // Set pin(s) to 0
|
|
PLATFORM_IO_PIN_GET, // Get value of pin
|
|
PLATFORM_IO_PIN_DIR_INPUT, // Configure pin(s) as input
|
|
PLATFORM_IO_PIN_DIR_OUTPUT, // Configure pin(s) as output
|
|
PLATFORM_IO_PIN_PULLUP, // Enable pullups on the pin(s)
|
|
PLATFORM_IO_PIN_PULLDOWN, // Enable pulldowns on the pin(s)
|
|
PLATFORM_IO_PIN_NOPULL, // Disable all pulls on the pin(s)
|
|
// Port operations
|
|
PLATFORM_IO_PORT_SET_VALUE, // Set port value
|
|
PLATFORM_IO_PORT_GET_VALUE, // Get port value
|
|
PLATFORM_IO_PORT_DIR_INPUT, // Configure port as input
|
|
PLATFORM_IO_PORT_DIR_OUTPUT // Configure port as output
|
|
};
|
|
(END inc/platform.h)
|
|
|
|
================================================================================
|
|
|
|
int platform_spi_exists( unsigned id );
|
|
u32 platform_spi_setup( unsigned id, int mode, u32 clock, unsigned cpol,
|
|
unsigned cpha, unsigned databits );
|
|
spi_data_type platform_spi_send_recv( unsigned id, spi_data_type data );
|
|
void platform_spi_select( unsigned id, int is_select );
|
|
|
|
TYPE: OPTIONAL
|
|
USED BY MODULE: spi
|
|
|
|
PURPOSE: SPI operations. eLua defines 4 "virtual" SPI interfaces. The function
|
|
platform_spi_exists() gets an identifier from 0 to 3 and returns 1 if the SPI
|
|
interface with the given identifier exists on the target machine, 0 ohterwise.
|
|
platform_spi_setup() is called to configure the SPI interface with the given
|
|
parameters, returning the actual clock that was set for the interface. The
|
|
actual data transfer is done by calling platform_spi_send_recv(), which executes
|
|
a SPI "cycle" (send one byte, receive one byte). Finally, platform_spi_select()
|
|
is used to set the state of the SPI SS (slave select) pin, if the target's SPI
|
|
interface provides this functionality.
|
|
|
|
================================================================================
|
|
|
|
int platform_uart_exists( unsigned id );
|
|
u32 platform_uart_setup( unsigned id, u32 baud, int databits, int parity,
|
|
int stopbits );
|
|
void platform_uart_send( unsigned id, u8 data );
|
|
int platform_uart_recv( unsigned id, unsigned timer_id, int timeout );
|
|
|
|
TYPE: OPTIONAL
|
|
USED BY MODULE: uart
|
|
ALSO USED BY: XMODEM, TERM over UART
|
|
|
|
PURPOSE: UART operations. eLua defines 4 "virtual" UART interfaces. The function
|
|
platform_uart_exists() gets an identifier from 0 to 3 and returns 1 if the UART
|
|
interface with the given identifier exists on the target machine, 0 ohterwise.
|
|
platform_uart_setup() is called to configure the SPI interface with the given
|
|
parameters, returning the actual baud that was set for the interface. The
|
|
actual data transfer is done by calling platform_uart_send to send a byte, and
|
|
platform_uart_recv to receive a byte. The receive function has a timeout than
|
|
can take different values:
|
|
|
|
- timeout == 0: receive without waiting for data. If a data byte is available
|
|
return it, otherwise return -1.
|
|
- timeout == PLATFORM_UART_INFINITE_TIMEOUT: wait until a data byte is available
|
|
and then return it. This will block indefinetely if no data is available.
|
|
- timeout > 0: if a data byte is available in the give time (expressed in us)
|
|
return id, otherwise return -1.
|
|
|
|
================================================================================
|
|
|
|
int platform_timer_exists( unsigned id );
|
|
void platform_timer_delay( unsigned id, u32 delay_us );
|
|
u32 platform_timer_op( unsigned id, int op, u32 data );
|
|
u32 platform_timer_get_diff_us( unsigned id, timer_data_type end,
|
|
timer_data_type start );
|
|
|
|
TYPE: OPTIONAL
|
|
USED BY MODULE: tmr, uart (for receive with timeout)
|
|
ALSO USED BY: XMODEM, TERM over UART
|
|
|
|
PURPOSE: timer operations. eLua defines 16 "virtual" timers. The function
|
|
platform_timer_exists() gets an identifier from 0 to 15 and returns 1 if the
|
|
timer with the given identifier exists on the target machine, 0 otherwise.
|
|
platform_timer_delay() will block the execution for the specified number of
|
|
microseconds, and platform_timer_get_diff_us() gets two timer values and returns
|
|
the time difference (in microseconds) between them.
|
|
platform_timer_op() executes the specified operation on the givem timer. The
|
|
operations are defined in an enum from inc/platform.h:
|
|
|
|
(BEGIN inc/platform.h)
|
|
// Timer operations
|
|
enum
|
|
{
|
|
PLATFORM_TIMER_OP_START, // Start the timer
|
|
PLATFORM_TIMER_OP_READ, // Read the value of timer
|
|
PLATFORM_TIMER_OP_SET_CLOCK, // Set the clock of the timer
|
|
PLATFORM_TIMER_OP_GET_CLOCK, // Read the clock of the timer
|
|
PLATFORM_TIMER_OP_GET_MAX_DELAY, // Get the maximum achievable delay
|
|
PLATFORM_TIMER_OP_GET_MIN_DELAY // Get the minimum achievable delay
|
|
};
|
|
(END inc/platform.h)
|
|
|
|
================================================================================
|
|
|
|
int platform_pwm_exists( unsigned id );
|
|
u32 platform_pwm_setup( unsigned id, u32 frequency, unsigned duty );
|
|
u32 platform_pwm_op( unsigned id, int op, u32 data );
|
|
|
|
TYPE: optional
|
|
USED BY MODULE: pwm
|
|
|
|
PURPOSE: PWM operations. eLua defines 16 "virtual" PWM blocks. The function
|
|
platform_pwm_exists() gets an identifier from 0 to 15 and returns 1 if the PWM
|
|
block with the given identifier exists on the target machinem, 0 otherwise.
|
|
platform_pwm_setup() is called to configure the SPI interface with the given
|
|
frequency and duty cycle (the duty cycle is a number from 0 to 100 representing
|
|
the duty cycle in percents).
|
|
Finally, platform_pwm_op() implements PWM specific operations. They are all
|
|
defined in an enum from inc/platform.h, shown below:
|
|
|
|
(BEGIN inc/platform.h)
|
|
// PWM operations
|
|
enum
|
|
{
|
|
PLATFORM_PWM_OP_START, // Start the PWM block
|
|
PLATFORM_PWM_OP_STOP, // Stop the PWM block
|
|
PLATFORM_PWM_OP_SET_CLOCK, // Set the base clock of the PWM block
|
|
PLATFORM_PWM_OP_GET_CLOCK // Get the base clock of the PWM block
|
|
};
|
|
(END inc/platform.h)
|
|
|
|
================================================================================
|
|
|
|
void platform_cpu_enable_interrupts();
|
|
void platform_cpu_disable_interrupts();
|
|
u32 platform_cpu_get_frequency();
|
|
|
|
TYPE: optional
|
|
USED BY MODULE: cpu
|
|
|
|
PURPOSE: CPU interfacing. It allows the user to control some of the CPU functions
|
|
directly from Lua. platform_cpu_enable_interrupts() enables the CPU interrupts
|
|
(globally), while platform_cpu_disable_interrupts() disables them.
|
|
platform_cpu_get_frequency() returns the CPU "core" frequency in Hz.
|
|
|
|
================================================================================
|
|
|
|
void platform_eth_send_packet( const void* src, u32 size );
|
|
u32 platform_eth_get_packet_nb( void* buf, u32 maxlen );
|
|
void platform_eth_force_interrupt();
|
|
u32 platform_eth_get_elapsed_time();
|
|
|
|
TYPE: optional
|
|
USED BY MODULE: net, also used by the generic TCP/IP support
|
|
|
|
PURPOSE: network support. These functions are used by uIP (the TCP/IP stack of
|
|
eLua) to implement TCP/IP services on top of the Ethernet ones (for platforms
|
|
that have an integrated Ethernet controller, or are using an external Ethernet
|
|
controller).
|
|
platform_eth_send_packet() sends the packet pointed by "src" with size "size"
|
|
over the network.
|
|
platform_eth_get_packet_nb() reads an Ethernet packet in "buf", without
|
|
exceeding "maxlen" of data. If an Ethernet packet is not available when this
|
|
function is called, it returns 0 immediately (non-blocking receive), otherwise
|
|
it returns a negative integer if the packet size is too large or the length of
|
|
the packet if it fits in "maxlen" bytes.
|
|
platform_eth_force_interrupt() is used to force an Ethernet receive interrupt.
|
|
This is needed because uIP's processing function is called from this Ethernet
|
|
interrupt handler alone.
|
|
platform_eth_get_elapsed_time() will return the approximate time (in ms) that
|
|
passed since the last call to platform_eth_get_elapsed_time(). It is used by uIP
|
|
to process periodic events.
|
|
|
|
For an example of how these functions should be implemented, take a look at the
|
|
LM3S backend (src/platform/lm3s/platform.c)
|