1
0
mirror of https://github.com/elua/elua.git synced 2025-01-08 20:56:17 +08:00
elua/docs/platform_interface.txt

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)