1
0
mirror of https://github.com/elua/elua.git synced 2025-01-25 01:02:54 +08:00

Fix minor indentation conflict.

Merge branch 'master' of https://github.com/elua/elua

Conflicts:
	src/platform/lm3s/platform.c
This commit is contained in:
James Snyder 2011-07-19 15:11:31 -05:00
commit 1a85900ac6
41 changed files with 1009 additions and 308 deletions

View File

@ -214,7 +214,8 @@ local menu =
{
{ "lm3s", "modules_lm3s.html", "refman_ps_lm3s" },
{ "str9", "modules_str9.html", "refman_ps_str9" },
{ "mbed", "modules_mbed.html", "refman_ps_mbed" }
{ "mbed", "modules_mbed.html", "refman_ps_mbed" },
{ "mizar32", "modules_mizar32.html", "refman_ps_mizar32" },
}
}
}

View File

@ -9,7 +9,7 @@ local sf = string.format
-- Data structure declarations
-- List here all the sections for which we're generating the documentation
local doc_sections = { "arch_platform", "refman_gen", "refman_ps_lm3s", "refman_ps_str9", "refman_ps_mbed" }
local doc_sections = { "arch_platform", "refman_gen", "refman_ps_lm3s", "refman_ps_str9", "refman_ps_mbed", "refman_ps_mizar32" }
-- List here all the components of each section
local components =
@ -18,7 +18,8 @@ local components =
refman_gen = { "bit", "pd", "cpu", "pack", "adc", "term", "pio", "uart", "spi", "tmr", "pwm", "net", "can", "rpc", "elua", "i2c" },
refman_ps_lm3s = { "disp" },
refman_ps_str9 = { "pio", "rtc" },
refman_ps_mbed = { "pio" }
refman_ps_mbed = { "pio" },
refman_ps_mizar32 = { "disp" },
}
-------------------------------------------------------------------------------

View File

@ -10,14 +10,14 @@ data_en =
-- Overview
overview = [[This part of the platform interface groups functions related to the timers of the MCU. It also makes provisions for using $virtual timers$ on any platform, see @#virtual@this section@
for details. Keep in mind that in the following paragraphs a $timer id$ can reffer to both a hardware timer or a virtual timer.]],
for details. Keep in mind that in the following paragraphs a $timer id$ can refer to both a hardware timer or a virtual timer.]],
-- Data structures, constants and types
structures =
{
{ text = "typedef u32 timer_data_type;",
name = "Timer data type",
desc = "This defines the data type used to specify delays and time intervals (which are always specifide in $microseconds$)."
desc = "This defines the data type used to specify delays and time intervals (which are always specified in $microseconds$)."
},
{ text = [[// Timer operations
@ -130,7 +130,7 @@ enum
},
{ sig = "u32 #platform_timer_get_diff_us#( unsigned id, timer_data_type end, timer_data_type start );",
desc = [[Return the time difference (in us) betweeen two timer values. This function is generic for all platforms, thus it is implemented in %src/common.c%.]],
desc = [[Return the time difference (in us) between two timer values. This function is generic for all platforms, thus it is implemented in %src/common.c%.]],
args =
{
"$id$ - the timer ID",
@ -141,7 +141,7 @@ enum
},
{ sig = "int #platform_timer_set_match_int#( unsigned id, u32 period_us, int type );",
desc = "Setup the timer match interrupt. Only available if interrupt support is enabed, check @inthandlers.html@here@ for details.",
desc = "Setup the timer match interrupt. Only available if interrupt support is enabled, check @inthandlers.html@here@ for details.",
args =
{
"$id$ - the timer ID",

View File

@ -81,7 +81,7 @@ data_en =
ret = "$status$ - 1 if no samples are being acquired, 0 if samples are pending acquisition."
},
{ sig = "#adc.setblocking#( id, mode )",
desc = "Set whether or not functions that request converted samples should wait for requested samples or return immediately with what is available.",
desc = "Set whether or not functions that request converted samples should wait for requested samples or return immediately with what is available. If this function is not called, each channel starts in blocking mode.",
args =
{
"$id$ - ADC channel ID.",

View File

@ -21,7 +21,7 @@ data_en =
args =
{
"$id$ - the ID of the I2C interface.",
"$speed$ - the speed of the I2C interface. It can be either $i2c.FAST$ (400KHz) or $i2c.SLOW$ (100KHz).",
"$speed$ - the clock frequency of the I2C interface. It can be $i2c.FAST$ (400KHz), $i2c.SLOW$ (100KHz) or a number giving the required I2C bus clock speed in Hz.",
},
ret = "the actual speed of the I2C interface."
},
@ -52,7 +52,7 @@ data_en =
args =
{
"$id$ - the ID of the I2C interface.",
"$data1$ - the data to send. It can be either a number between 0 and 255, a string or a table (array).",
"$data1$ - the data to send. It can be either a number between 0 and 255, a string or a table (array) of numbers.",
"$data2 (optional)$ - the second data to send.",
"$datan (optional)$ - the %n%-th data to send."
},

View File

@ -0,0 +1,41 @@
-- eLua reference manual - platform data
data_en =
{
-- Title
title = "eLua reference manual - Mizar32 disp module",
-- Menu name
menu_name = "disp",
-- Overview
overview = [[This module contains functions to drive the 16x2 character LED panel for the Mizar32.]],
-- Functions
funcs =
{
{ sig = "#mizar32.disp.clear#()",
desc = "Clear the display and move the cursor to the top left (position 1,1)."
},
{ sig = "#mizar32.disp.goto#( row, column )",
desc = "Move the cursor to the specified row and column.",
args =
{
"$row$ - A number (1 or 2) giving the row you want to move to.",
"$column$ - A number (1 to 16) giving the character position within that row."
}
},
{ sig = "#mizar32.disp.print#( message )",
desc = "Display characters at the current cursor position, moving the cursor right after each character",
args =
{
"$message$ - A string of ASCII text to be written on the display."
}
},
},
}
data_pt = data_en

View File

@ -49,7 +49,7 @@ Here's an alphabetically ordered non-exhaustive list of contributors:
- Renaud Cerrato - Initial EVK1101 AVR32 port
- Robert G. Jakabosky - for porting his excellent link:elua_egc.html[emergency garbage collector] patch to eLua
- Roberto Ierusalimschy, Luiz Henrique Figueiredo, Waldemar Celles - for http://www.lua.org[Lua] :)
- Sergio Sorrenti and Martin Guy - AVR32 support, http://www.simplemachines.it/index.php?option=com_content&view=article&id=13&Itemid=24[Mizar32] port, testing
- http://simplemachines.it[SimpleMachines] - AVR32 support, http://www.simplemachines.it/index.php?option=com_content&view=article&id=13&Itemid=24[Mizar32] port, testing
- Téo Benjamin, Ives Cunha, Rafael Barmak - Pong, TetrIves, SpaceShip games and http://wiki.eluaproject.net/Manfredo[Manfredo], a GPS guided robot, powered by eLua.
- Vagner Nascimento and Carlos Eduardo Deodoro - eLua Web Builder
- The eLua users community on our https://lists.berlios.de/mailman/listinfo/elua-dev[discussion list] and http://wiki.eluaproject.net[eLua Wiki]

View File

@ -0,0 +1,5 @@
$$HEADER$$
<h3>Reference manual - Mizar32 platform dependent modules</h3>
<p>This paragraph presents all the modules specific to the <a href="status.html">Mizar32</a> platform.</p>
$$FOOTER$$

View File

@ -59,7 +59,7 @@ install it, then open the com0com serial port manager to create your virtual
serial port pairs. Then give it a little spin to get used to how it works. Supposing
that you created COM10 and COM11 as a virtual serial port pair, try this:
- start your terminal emulator program. My preffered terminal emulator program in
- start your terminal emulator program. My preferred terminal emulator program in
Windows is http://www.ayera.com/teraterm/[TeraTerm], but you can use any emulator
you want. Open COM10 at baud 115200.
- start another instance of the terminal emulator, but this time open COM11 at baud 115200.

View File

@ -74,6 +74,16 @@
#endif
#endif
// MMCFS uses the virtual timer to implement its timeouts
#if defined( BUILD_MMCFS ) && (!defined( VTMR_NUM_TIMERS ) || VTMR_NUM_TIMERS == 0)
#error "BUILD_MMCFS needs virtual timer support. Define VTMR_NUM_TIMERS > 0"
#endif
// MMCFS tick runs off VTMR timer so these values must be the same
#if defined( BUILD_MMCFS ) && MMCFS_TICK_HZ != VTMR_FREQ_HZ
#error "MMCFS_TICK_HZ must be equal to VTMR_FREQ_HZ"
#endif
// CON_BUF_SIZE needs BUF_ENABLE_UART and CON_UART_ID
#if defined( CON_BUF_SIZE )
#if !defined( BUF_ENABLE_UART )

View File

@ -224,7 +224,7 @@ 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 )
{
timer_data_type temp;
u32 freq;
u32 freq, res;
freq = platform_timer_op( id, PLATFORM_TIMER_OP_GET_CLOCK, 0 );
if( start < end )
@ -233,7 +233,17 @@ u32 platform_timer_get_diff_us( unsigned id, timer_data_type end, timer_data_typ
end = start;
start = temp;
}
return ( ( u64 )( start - end ) * 1000000 ) / freq;
res = ( ( u64 )( start - end ) * 1000000 ) / freq;
// The result always ends up being given to lua_pushinteger() which turns
// 0x80000000-0xFFFFFFFF into negative numbers, so max out at 2^31-1 to
// avoid getting negative results from tmr.getmaxdelay(tmr.VIRT0) and
// tmr.gettimediff(N, small, large).
#define MAX_U32 ( ~(u32)0 >> 1 )
if ( res > MAX_U32 ) res = MAX_U32;
return res;
}
#ifdef BUILD_INT_HANDLERS

View File

@ -67,6 +67,25 @@ BYTE CardType; /* b0:MMC, b1:SDC, b2:Block addressing */
static
BYTE PowerFlag = 0; /* indicates if "power" is on */
/*-----------------------------------------------------------------------*/
/* Find the value to set in Timer1 or Timer2 to obtain a timeout of at */
/* least N milliseconds. */
/* */
/* Timer1 and Timer2 are decremented by the virtual timer interrupt, */
/* which is free-running and will sometimes decrement TimerN immediately */
/* so to wait for N ms to pass, you need to wait for N+1 ticks to occur. */
/* */
/* Usage example: */
/* Timer1 = set_Timer_ms(N); */
/* do { whatever } while (Timer1); */
/*-----------------------------------------------------------------------*/
static UINT set_Timer_ms(UINT ms)
{
UINT ticks = ms / MMCFS_TICK_MS;
return (ticks > 0 ? ticks : 1) + 1;
}
/*-----------------------------------------------------------------------*/
/* Transmit a byte to MMC via SPI (Platform dependent) */
/*-----------------------------------------------------------------------*/
@ -109,7 +128,7 @@ BYTE wait_ready (void)
{
BYTE res;
Timer2 = 500/MMCFS_TICK_MS; /* Wait for ready in timeout of 500ms */
Timer2 = set_Timer_ms(500); /* Wait for ready in timeout of 500ms. */
rcvr_spi();
do
res = rcvr_spi();
@ -205,8 +224,7 @@ BOOL rcvr_datablock (
{
BYTE token;
Timer1 = 100/MMCFS_TICK_MS ? 100/MMCFS_TICK_MS : 1;
Timer1 = set_Timer_ms(100);
do { /* Wait for data packet in timeout of 100ms */
token = rcvr_spi();
} while ((token == 0xFF) && Timer1);
@ -326,7 +344,7 @@ DSTATUS disk_initialize (
SELECT(); /* CS = L */
ty = 0;
if (send_cmd(CMD0, 0) == 1) { /* Enter Idle state */
Timer1 = 1000/MMCFS_TICK_MS; /* Initialization timeout of 1000 msec */
Timer1 = set_Timer_ms(1000); /* Initialization timeout of 1000 msec */
if (send_cmd(CMD8, 0x1AA) == 1) { /* SDC Ver2+ */
for (n = 0; n < 4; n++) ocr[n] = rcvr_spi();
if (ocr[2] == 0x01 && ocr[3] == 0xAA) { /* The card can work at vdd range of 2.7-3.6V */
@ -583,6 +601,7 @@ DRESULT disk_ioctl (
/*-----------------------------------------------------------------------*/
/* Device Timer Interrupt Procedure (Platform dependent) */
/*-----------------------------------------------------------------------*/
/* This function must be called in period of 10ms */
void disk_timerproc( void )

View File

@ -392,10 +392,10 @@ static const LUA_REG_TYPE pio_port_map[] =
const LUA_REG_TYPE pio_map[] =
{
{ LSTRKEY( "decode" ), LFUNCVAL( pio_decode ) },
#if LUA_OPTIMIZE_MEMORY > 0
{ LSTRKEY( "pin" ), LROVAL( pio_pin_map ) },
{ LSTRKEY( "port" ), LROVAL( pio_port_map ) },
{ LSTRKEY( "decode" ), LFUNCVAL( pio_decode ) },
{ LSTRKEY( "INPUT" ), LNUMVAL( PIO_DIR_INPUT ) },
{ LSTRKEY( "OUTPUT" ), LNUMVAL( PIO_DIR_OUTPUT ) },
{ LSTRKEY( "PULLUP" ), LNUMVAL( PLATFORM_IO_PIN_PULLUP ) },

View File

@ -87,6 +87,7 @@
_ROM( AUXLIB_UART, luaopen_uart, uart_map )\
_ROM( AUXLIB_PIO, luaopen_pio, pio_map )\
_ROM( AUXLIB_PWM, luaopen_pwm, pwm_map )\
_ROM( AUXLIB_I2C, luaopen_i2c, i2c_map )\
_ROM( AUXLIB_SPI, luaopen_spi, spi_map )\
_ROM( AUXLIB_TMR, luaopen_tmr, tmr_map )\
_ROM( AUXLIB_TERM, luaopen_term, term_map )\
@ -104,7 +105,7 @@
// Virtual timers (0 if not used)
#define VTMR_NUM_TIMERS 4
#define VTMR_FREQ_HZ 4
#define VTMR_FREQ_HZ 10
// Number of resources (0 if not available/not implemented)
#define NUM_PIO 4
@ -116,6 +117,7 @@
#define NUM_TIMER 3
#endif
#define NUM_PWM 7
#define NUM_I2C 1
#define NUM_ADC 8
#define NUM_CAN 0

View File

@ -67,7 +67,7 @@
// Virtual timers (0 if not used)
#define VTMR_NUM_TIMERS 4
#define VTMR_FREQ_HZ 4
#define VTMR_FREQ_HZ 10
// Number of resources (0 if not available/not implemented)
#define NUM_PIO 2

View File

@ -25,19 +25,30 @@
//#define BUILD_RFS
//#define BUILD_SERMUX
#if ELUA_CPU == AT32UC3A0128
#if defined( ELUA_CPU_AT32UC3A0128 )
// Build options for 120KB image
# define RAM_SIZE 0x8000
#else
// Build options for 256KB and 512KB flash
# define RAM_SIZE 0x10000
# define BUILD_ADC
# define BUILD_TERM
# define BUILD_UIP
# define ENABLE_DISP
#endif
#ifdef BUILD_UIP
//#define BUILD_DHCPC
#define BUILD_DNS
#define BUILD_CON_TCP
//#define BUILD_CON_TCP
#endif
// ****************************************************************************
// Auxiliary libraries that will be compiled for this platform
// The name of the platform specific libs table
#ifdef ENABLE_DISP
#define PS_LIB_TABLE_NAME "mizar32"
#endif
// *****************************************************************************
@ -98,7 +109,13 @@
#define RPCLINE
#endif
#if ELUA_CPU == AT32UC3A0128
#ifdef PS_LIB_TABLE_NAME
#define PLATLINE _ROM( PS_LIB_TABLE_NAME, luaopen_platform, platform_map )
#else
#define PLATLINE
#endif
#if defined( ELUA_CPU_AT32UC3A0128 )
// Minimal ROM modules, to fit in 120KB
#define LUA_PLATFORM_LIBS_ROM\
@ -113,6 +130,7 @@
_ROM( AUXLIB_UART, luaopen_uart, uart_map )\
_ROM( AUXLIB_PIO, luaopen_pio, pio_map )\
_ROM( AUXLIB_PWM, luaopen_pwm, pwm_map )\
_ROM( AUXLIB_I2C, luaopen_i2c, i2c_map )\
_ROM( AUXLIB_SPI, luaopen_spi, spi_map )\
_ROM( AUXLIB_TMR, luaopen_tmr, tmr_map )\
NETLINE\
@ -123,7 +141,8 @@
_ROM( AUXLIB_BIT, luaopen_bit, bit_map )\
_ROM( AUXLIB_PACK, luaopen_pack, pack_map )\
_ROM( AUXLIB_TERM, luaopen_term, term_map )\
_ROM( LUA_MATHLIBNAME, luaopen_math, math_map )
_ROM( LUA_MATHLIBNAME, luaopen_math, math_map )\
PLATLINE\
#endif
@ -132,7 +151,7 @@
// Virtual timers (0 if not used)
#define VTMR_NUM_TIMERS 4
#define VTMR_FREQ_HZ 4
#define VTMR_FREQ_HZ 10
// Number of resources (0 if not available/not implemented)
#define NUM_PIO 4
@ -144,6 +163,7 @@
#define NUM_TIMER 3
#endif
#define NUM_PWM 7 // PWM7 is on GPIO50
#define NUM_I2C 1
#define NUM_ADC 8 // Though ADC3 pin is the Ethernet IRQ
#define NUM_CAN 0
@ -194,7 +214,7 @@
// Allocator data: define your free memory zones here in two arrays
// (start address and end address)
#define MEM_START_ADDRESS { ( void* )end, ( void* )( SDRAM + ELUA_FIRMWARE_SIZE ) }
#define MEM_END_ADDRESS { ( void* )( 0x8000 - STACK_SIZE_TOTAL - 1 ), ( void* )( SDRAM + SDRAM_SIZE - 1 ) }
#define MEM_END_ADDRESS { ( void* )( RAM_SIZE - STACK_SIZE_TOTAL - 1 ), ( void* )( SDRAM + SDRAM_SIZE - 1 ) }
// Interrupt queue size
#define PLATFORM_INT_QUEUE_LOG_SIZE 5

View File

@ -1,6 +1,6 @@
-- Configuration file for the AVR32 microcontrollers
specific_files = "crt0.s trampoline.s platform.c exception.s intc.c pm.c flashc.c pm_conf_clocks.c usart.c gpio.c tc.c spi.c platform_int.c adc.c pwm.c ethernet.c"
specific_files = "crt0.s trampoline.s platform.c exception.s intc.c pm.c flashc.c pm_conf_clocks.c usart.c gpio.c tc.c spi.c platform_int.c adc.c pwm.c i2c.c ethernet.c disp.c"
addm( "FORAVR32" )
-- See board.h for possible BOARD values.

View File

@ -1,6 +1,6 @@
# Configuration file for the AVR32 microcontrollers
specific_files = "crt0.s trampoline.s platform.c exception.s intc.c pm.c flashc.c pm_conf_clocks.c usart.c gpio.c tc.c spi.c platform_int.c adc.c pwm.c ethernet.c"
specific_files = "crt0.s trampoline.s platform.c exception.s intc.c pm.c flashc.c pm_conf_clocks.c usart.c gpio.c tc.c spi.c platform_int.c adc.c pwm.c i2c.c ethernet.c disp.c"
comp.Append(CPPDEFINES = 'FORAVR32')
# See board.h for possible BOARD values.

115
src/platform/avr32/disp.c Normal file
View File

@ -0,0 +1,115 @@
// eLua module for Mizar32 LCD character display
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
#include "platform.h"
#include "lrotable.h"
#include "platform_conf.h"
#include "disp.h"
#include "i2c.h"
// Declaration to save/restore the I2C clock rate
extern u32 i2c_delay;
static u32 old_i2c_delay;
// Functions that bracket all I2C packets to the LCD module,
// to save, change and restore the I2C clock rate.
static void disp_start()
{
old_i2c_delay = i2c_delay;
i2c_delay = REQ_CPU_FREQ / DISP_BUS_FREQ / 2;
}
static void disp_stop()
{
i2c_delay = old_i2c_delay;
}
// Utility function: pause for N * 5ms
static void disp_delay(unsigned long n)
{
// Code stolen from sdramc.c::sdramc_ck_delay()
// Use the CPU cycle counter (CPU and HSB clocks are the same).
u32 delay_start_cycle = Get_system_register(AVR32_COUNT);
u32 delay_end_cycle = delay_start_cycle + n * DISP_DELAY_TICKS;
// To be safer, the end of wait is based on an inequality test, so CPU cycle
// counter wrap around is checked.
if (delay_start_cycle > delay_end_cycle)
{
while ((unsigned long)Get_system_register(AVR32_COUNT) > delay_end_cycle);
}
while ((unsigned long)Get_system_register(AVR32_COUNT) < delay_end_cycle);
}
// Generic function to emit an LCD command byte, normally used in a tail call.
static int disp_command(unsigned char command)
{
disp_start();
i2c_start_cond();
i2c_write_byte( DISP_CMD );
i2c_write_byte( command );
i2c_stop_cond();
disp_stop();
disp_delay(1);
return 0;
}
//Lua: mizar32.disp.clear()
static int disp_clear(lua_State *L) {
return disp_command( DISP_CMD_CLEAR );
}
//Lua: mizar32.disp.goto( row, col )
static int disp_goto(lua_State *L) {
unsigned row = luaL_checkinteger( L, 1 );
unsigned col = luaL_checkinteger( L, 2 );
unsigned address;
if ( row < 1 || row > 2 || col < 1 || col > 16 ) {
return luaL_error( L, "row/column must be 1-2 and 1-16" );
}
address = ( row - 1 ) * 0x40 + ( col - 1 ) ;
return disp_command( DISP_CMD_DDADDR + address );
}
//Lua: mizar32.disp.print( string )
static int disp_print(lua_State *L) {
const char *str = luaL_checkstring( L, 1 );
int nbytes = 0;
disp_start();
i2c_start_cond();
i2c_write_byte( DISP_DATA );
// Mizar32 LCD module has a maximum of 32 bytes per packet
while ( *str && nbytes < 32 ) {
i2c_write_byte( *str++ );
nbytes++;
}
i2c_stop_cond();
disp_stop();
disp_delay(nbytes);
return 0;
}
#define MIN_OPT_LEVEL 2
#include "lrodefs.h"
// Module function map
const LUA_REG_TYPE disp_map[] =
{
{ LSTRKEY( "clear" ), LFUNCVAL( disp_clear ) },
{ LSTRKEY( "goto" ), LFUNCVAL( disp_goto ) },
{ LSTRKEY( "print" ), LFUNCVAL( disp_print ) },
};
LUALIB_API int luaopen_disp( lua_State *L )
{
LREGISTER( L, AUXLIB_DISP, disp_map );
}

44
src/platform/avr32/disp.h Normal file
View File

@ -0,0 +1,44 @@
// Mizar32 LCD character display
#ifndef __DISP_H__
#define __DISP_H__
// See the Ampire datasheet http://home.comet.bg/datasheets/LCD/AC-162B.pdf
// and http://embeddedtutorial.com/2010/01/interfacing-lcd-with-8051/
// I2C bus frequency that the LCD display runs at: 20kHz max
#define DISP_BUS_FREQ 20000
// Pause required after every command byte, and n*delay when sending N
// characters of data (or of commands): 5 milliseconds
// Expressed in CPU clock ticks.
// 5 and 6ms seem not to work when doing
// mizar32.disp.clear() mizar32.disp.print("Hello world")
// or
// for i = 1,16 do mizar32.disp.goto(2,i) mizar32.disp.print("X") end
// but 7ms works for both.
#define DISP_DELAY_TICKS (REQ_CPU_FREQ * 7 / 1000)
// I2C slave addresses for command bytes and data strings
// Command address is followed by a dingle byte giving the command to perform
// Data address is followed by multiple bytes of ASCII data to display
// on the character display at the current cursor location.
#define DISP_CMD 0xF6
#define DISP_DATA 0xF2
// Command bytes
// "Clear display: Write "20H" to DDRAM and set DDRAM address to "00H" from AC"
#define DISP_CMD_CLEAR 1
// "Return Home: Sets DDRAM address to "00H" from AC and return cursor to its
// original position if shifted."
#define DISP_CMD_HOME 2 // Bit 0: don't care
// "Sets DD RAM address in address counter"
#define DISP_CMD_DDADDR 128
// Bits 0-7 are the address:
// 00-0F are the first line
// 40-4F are the second line
#endif

342
src/platform/avr32/i2c.c Normal file
View File

@ -0,0 +1,342 @@
// This file implements I2C protocol on AVR32 devices in eLua.
//
// For reasons outlined below, it does not use the Atmel TWI hardware
// but implements it by bit-banging two GPIO lines.
//
// Martin Guy <martinwguy@gmail.com>, June 2011
// AVR32 has two families of "two wire" interfaces, both of them inadequate:
//
// AT32UC3A[01]* and AT32UC3B* have a single "TWI" "I2C-compatibile" interface
// that can be switched between master and slave modes;
// AT32UC3A[34]* and AT32UC3C* devices have separate "TWIM" and "TWIS"
// interfaces, three of each in the C series.
// Their registers and functionality are completely different,
//
// All currently supported eLua AVR32 targets
// (EVK1100 Mizar32 == AT32UC3A0* and EVK1101 == AT32UC3B*)
// have one "TWI" interface.
//
// 1) "TWI" hardware limitations
//
// The only repeated start sequence that TWI can generate as master is
// START/ADDRESS(W)/WRITE 1, 2 or 3 bytes/START/ADDRESS(R)/READ n BYTES/STOP.
//
// It cannot emit START/ADDRESS(R/W)/STOP, which is necessary to probe
// for the presence of a device on the bus. Their SDK writes a single 0 bytes
// to do this, which has different effects on different hardware.
// This makes I2C unimplementable using this variant of the hardware.
//
// Worse, you have to have all the data in hand before you start any transfer
// because if you fail to rewrite the "Transmit Holding Register" with the next
// byte while the current byte is being sent, the hardware automatically
// generates a STOP without asking you.
// This makes eLua's current Lua and C I2C interfaces unimplementable.
//
// 2) "TWIM" and "TWIS" hardware limitations
//
// This seems to be able to generate a wider range of repeated start signals
// but the amount of data you can send or receive in one packet is limited to
// 255 bytes.
//
// 3) Bit-banging them as GPIO pins
//
// Given the two sets of incompatible hardware and the fact that neither is
// capable either of speaking I2C or of implementing the current eLua I2C
// interface, we just bit-bang the IO pins.
//
// Some of the chips (e.g. AVR32UC3[01]*) have a GPIO open-collector mode,
// which sounds promising, but others (AVR32UC3A[34], AVR32UC3[BC]) do not
// so we obtain a pseudo-open-collector mode by switching the GPIO pins
// between output (always low) and input (of high impedance).
//
// The disadvantage of bit-banging GPIO pins instead of using the TWI hardware
// is that in TWI mode, the pins "are open-drain outputs with slew-rate
// limitation and inputs with spike-filtering" (AT32UC3A Datasheet, para 8.3).
// In GPIO mode, a "glitch filter" is available to reject pulses of 1 CPU cycle
// but this only affects the interrupt function, not the value read from the
// PVR register. (para 22.4.8)
// This first hack only support a single I2C channel and is only tested on the
// currently supported hardware (AVR32UC3A0*), all of which has a single TWI
// interface.
// To extend it to have multiple I2C channels you need to turn the variables
// started, delay, sda_regs, scl_regs
// and the constants
// {SDA,SCL}_{PIN,PORT,PINMASK}
// into arrays[NUM_I2C] and index them with id.
#include "platform_conf.h"
#include "compiler.h"
#include "gpio.h"
#include "i2c.h"
// Which port/pins are used for I2C?
#if defined(ELUA_CPU_AT32UC3A0128) || \
defined(ELUA_CPU_AT32UC3A0256) || \
defined(ELUA_CPU_AT32UC3A0512) || \
defined(ELUA_CPU_AT32UC3A1128) || \
defined(ELUA_CPU_AT32UC3A1256) || \
defined(ELUA_CPU_AT32UC3A1512)
// One master-slave TWI interface
# define SDA_PIN AVR32_PIN_PA29
# define SCL_PIN AVR32_PIN_PA30
#elif defined(ELUA_CPU_AT32UC3A364) || defined(ELUA_CPU_AT32UC3A364S) || \
defined(ELUA_CPU_AT32UC3A3128) || defined(ELUA_CPU_AT32UC3A3128S) || \
defined(ELUA_CPU_AT32UC3A3256) || defined(ELUA_CPU_AT32UC3A3256S) || \
defined(ELUA_CPU_AT32UC3A464) || defined(ELUA_CPU_AT32UC3A464S) || \
defined(ELUA_CPU_AT32UC3A4128) || defined(ELUA_CPU_AT32UC3A4128S) || \
defined(ELUA_CPU_AT32UC3A4256) || defined(ELUA_CPU_AT32UC3A4256S)
// The first of the two TWIM/TWIS interfaces, in pin configuration A
# define SDA_PIN AVR32_PIN_PA25
# define SCL_PIN AVR32_PIN_PA26
#elif defined(ELUA_CPU_AT32UC3B064) || \
defined(ELUA_CPU_AT32UC3B0128) || \
defined(ELUA_CPU_AT32UC3B0256) || \
defined(ELUA_CPU_AT32UC3B0512) || \
defined(ELUA_CPU_AT32UC3B164) || \
defined(ELUA_CPU_AT32UC3B1128) || \
defined(ELUA_CPU_AT32UC3B1256) || \
defined(ELUA_CPU_AT32UC3B1512)
// One master-slave TWI interface
# define SDA_PIN AVR32_PIN_PA10
# define SCL_PIN AVR32_PIN_PA09
#elif defined(ELUA_CPU_AT32UC3C064C) || \
defined(ELUA_CPU_AT32UC3C0128C) || \
defined(ELUA_CPU_AT32UC3C0256C) || \
defined(ELUA_CPU_AT32UC3C0512C) || \
defined(ELUA_CPU_AT32UC3C164C) || \
defined(ELUA_CPU_AT32UC3C1128C) || \
defined(ELUA_CPU_AT32UC3C1256C) || \
defined(ELUA_CPU_AT32UC3C1512C) || \
defined(ELUA_CPU_AT32UC3C264C) || \
defined(ELUA_CPU_AT32UC3C2128C) || \
defined(ELUA_CPU_AT32UC3C2256C) || \
defined(ELUA_CPU_AT32UC3C2512C)
// One master-slave TWI interface
# define SDA_PIN AVR32_PIN_PC02
# define SCL_PIN AVR32_PIN_PC03
#else
# error "I2C pin assignment is unknown for this CPU"
#endif
// Split these into port and pinmask
#define SDA_PORT ( SDA_PIN >> 5 )
#define SCL_PORT ( SCL_PIN >> 5 )
#define SDA_PINMASK ( 1 << ( SDA_PIN & 31 ) )
#define SCL_PINMASK ( 1 << ( SCL_PIN & 31 ) )
// The set of GPIO registers we will be using for each bus line.
// In practice, these two will always have the same value. Ho hum.
static volatile avr32_gpio_port_t *sda_regs =
&AVR32_GPIO.port[ SDA_PORT ];
static volatile avr32_gpio_port_t *scl_regs =
&AVR32_GPIO.port[ SCL_PORT ];
// Half an I2C bus clock cycle, as a number of HSB(==CPU) clock cycles;
// Be default, use the slow mode setting.
// This is exported to the LCD display driver ("disp") so that it can
// change the bus speed as required by the LCD, then restore it.
u32 i2c_delay = REQ_CPU_FREQ / 100000 / 2;
// Local functions used by the bit-banger
static void I2CDELAY(void); // Pause for half an I2C bus clock cycle
static int READSCL(void); // Set SCL as input and return current level of line
static int READSDA(void); // Set SDA as input and return current level of line
static void CLRSCL(void); // Actively drive SCL signal low
static void CLRSDA(void); // Actively drive SDA signal low
static void ARBITRATION_LOST(void); // Bus control was lost
// ************************
// The bitbanger itself, taken from http://en.wikipedia.org/wiki/I2C
// We don't use GPIO open-drain mode, which is not available on all hardware
// models. Instead, we use two modes to simulate open-drain:
// output of 0 and input.
u32 i2c_setup( u32 speed )
{
// First, set both pins as high-impedance inputs to avoid startup glitches
sda_regs->oderc = SDA_PINMASK;
scl_regs->oderc = SCL_PINMASK;
// When they are outputs, they will always output 0.
sda_regs->ovrc = SDA_PINMASK;
scl_regs->ovrc = SCL_PINMASK;
// Let the GPIO hardware control these pins
sda_regs->gpers = SDA_PINMASK;
scl_regs->gpers = SCL_PINMASK;
// Figure out how many clock cycles correspond to half a clock waveform.
i2c_delay = REQ_CPU_FREQ / speed / 2;
return speed;
}
// Are we between a start bit and a stop bit?
static int started = 0;
void i2c_start_cond(void)
{
if (started) {
// if started, do a restart cond
// set SDA to 1
READSDA();
I2CDELAY();
// Clock stretching
while (READSCL() == 0)
; // You can add a timeout to this loop to
// recover from SCL being stuck low.
}
if (READSDA() == 0)
ARBITRATION_LOST();
// SCL is high, set SDA from 1 to 0
CLRSDA();
I2CDELAY();
CLRSCL();
started = true;
}
void i2c_stop_cond(void)
{
/* set SDA to 0 */
CLRSDA();
I2CDELAY();
/* Clock stretching */
while (READSCL() == 0)
; /* You should add timeout to this loop */
/* SCL is high, set SDA from 0 to 1 */
if (READSDA() == 0)
ARBITRATION_LOST();
I2CDELAY();
started = false;
}
/* Write a bit to I2C bus */
static void i2c_write_bit(int bit)
{
if (bit)
READSDA();
else
CLRSDA();
I2CDELAY();
/* Clock stretching */
while (READSCL() == 0)
; /* You should add timeout to this loop */
/* SCL is high, now data is valid */
/* If SDA is high, check that nobody else is driving SDA */
if (bit && READSDA() == 0)
ARBITRATION_LOST();
I2CDELAY();
CLRSCL();
}
/* Read a bit from I2C bus */
static int i2c_read_bit(void)
{
int bit;
/* Let the slave drive data */
READSDA();
I2CDELAY();
/* Clock stretching */
while (READSCL() == 0)
; /* You should add timeout to this loop */
/* SCL is high, now data is valid */
bit = READSDA();
I2CDELAY();
CLRSCL();
return bit;
}
/* Write a byte to I2C bus. Return 0 if ack by the slave */
int i2c_write_byte(unsigned char byte)
{
unsigned bit;
int nack;
for (bit = 0; bit < 8; bit++) {
i2c_write_bit((byte & 0x80) != 0);
byte <<= 1;
}
nack = i2c_read_bit();
return nack;
}
/* Read a byte from I2C bus */
unsigned char i2c_read_byte(int nack)
{
unsigned char byte = 0;
unsigned bit;
for (bit = 0; bit < 8; bit++)
byte = (byte << 1) | i2c_read_bit();
i2c_write_bit(nack);
return byte;
}
//*******************
// Low-level functions used by the bit-banger
// Pause for half an I2C bus clock cycle
static void I2CDELAY()
{
// Code stolen from sdramc.c::sdramc_ck_delay()
// Use the CPU cycle counter (CPU and HSB clocks are the same).
u32 delay_start_cycle = Get_system_register(AVR32_COUNT);
u32 delay_end_cycle = delay_start_cycle + i2c_delay;
// To be safer, the end of wait is based on an inequality test, so CPU cycle
// counter wrap around is checked.
if (delay_start_cycle > delay_end_cycle)
{
while ((unsigned long)Get_system_register(AVR32_COUNT) > delay_end_cycle);
}
while ((unsigned long)Get_system_register(AVR32_COUNT) < delay_end_cycle);
}
// Set SCL as input and return current level of line
static int READSCL()
{
scl_regs->oderc = SCL_PINMASK;
return ( scl_regs->pvr & SCL_PINMASK ) ? 1 : 0;
}
// Set SDA as input and return current level of line
static int READSDA()
{
sda_regs->oderc = SDA_PINMASK;
return ( sda_regs->pvr & SDA_PINMASK ) ? 1 : 0;
}
// Actively drive SCL signal low
static void CLRSCL(void)
{
scl_regs->oders = SCL_PINMASK;
}
// Actively drive SDA signal low
static void CLRSDA(void)
{
sda_regs->oders = SDA_PINMASK;
}
// Bus control was lost.
// Not currently used. With a higher-level I2C interface, this can do a
// longjmp back to the eLua C interface routine which can retry the transfer
// when the bus is free.
static void ARBITRATION_LOST(void)
{
}

7
src/platform/avr32/i2c.h Normal file
View File

@ -0,0 +1,7 @@
// Declarations for the low-level AVR32 I2C driver for eLua
u32 i2c_setup( u32 speed ); // speed is in Hz
void i2c_start_cond( void );
void i2c_stop_cond( void );
int i2c_write_byte( unsigned char byte ); // returns 0 if acked by slave
unsigned char i2c_read_byte( int nack );

View File

@ -15,7 +15,6 @@
#include "platform_conf.h"
#include "common.h"
#include "buf.h"
#include "spi.h"
#ifdef BUILD_MMCFS
#include "diskio.h"
#endif
@ -40,6 +39,7 @@
#include "spi.h"
#include "adc.h"
#include "pwm.h"
#include "i2c.h"
// UIP sys tick data
// NOTE: when using virtual timers, SYSTICKHZ and VTMR_FREQ_HZ should have the
@ -145,10 +145,12 @@ int platform_init()
// Setup clocks
if( PM_FREQ_STATUS_FAIL == pm_configure_clocks( &pm_freq_param ) )
return PLATFORM_ERR;
#ifdef FOSC32
// Select the 32-kHz oscillator crystal
pm_enable_osc32_crystal (&AVR32_PM );
// Enable the 32-kHz clock
pm_enable_clk32_no_wait( &AVR32_PM, AVR32_PM_OSCCTRL32_STARTUP_0_RCOSC );
#endif
// Initialize external memory if any.
#ifdef AVR32_SDRAMC
@ -961,6 +963,49 @@ u32 platform_pwm_op( unsigned id, int op, u32 data)
return 0;
}
// ****************************************************************************
// I2C support
u32 platform_i2c_setup( unsigned id, u32 speed )
{
return i2c_setup(speed);
}
void platform_i2c_send_start( unsigned id )
{
i2c_start_cond();
}
void platform_i2c_send_stop( unsigned id )
{
i2c_stop_cond();
}
int platform_i2c_send_address( unsigned id, u16 address, int direction )
{
// Convert enum codes to R/w bit value.
// If TX == 0 and RX == 1, this test will be removed by the compiler
if ( ! ( PLATFORM_I2C_DIRECTION_TRANSMITTER == 0 &&
PLATFORM_I2C_DIRECTION_RECEIVER == 1 ) ) {
direction = ( direction == PLATFORM_I2C_DIRECTION_TRANSMITTER ) ? 0 : 1;
}
// Low-level returns nack (0=acked); we return ack (1=acked).
return ! i2c_write_byte( (address << 1) | direction );
}
int platform_i2c_send_byte( unsigned id, u8 data )
{
// Low-level returns nack (0=acked); we return ack (1=acked).
return ! i2c_write_byte( data );
}
int platform_i2c_recv_byte( unsigned id, int ack )
{
return i2c_read_byte( !ack );
}
// ****************************************************************************
// Network support
@ -1045,3 +1090,42 @@ u32 platform_eth_get_elapsed_time()
}
#endif
// ****************************************************************************
// Platform specific modules go here
#ifdef PS_LIB_TABLE_NAME
#define MIN_OPT_LEVEL 2
#include "lua.h"
#include "lauxlib.h"
#include "lrotable.h"
#include "lrodefs.h"
extern const LUA_REG_TYPE disp_map[];
const LUA_REG_TYPE platform_map[] =
{
#if LUA_OPTIMIZE_MEMORY > 0
{ LSTRKEY( "disp" ), LROVAL( disp_map ) },
#endif
{ LNILKEY, LNILVAL }
};
LUALIB_API int luaopen_platform( lua_State *L )
{
#if LUA_OPTIMIZE_MEMORY > 0
return 0;
#else // #if LUA_OPTIMIZE_MEMORY > 0
luaL_register( L, PS_LIB_TABLE_NAME, platform_map );
// Setup the new tables inside platform table
lua_newtable( L );
luaL_register( L, NULL, disp_map );
lua_setfield( L, -2, "disp" );
return 1;
#endif // #if LUA_OPTIMIZE_MEMORY > 0
}
#endif // #ifdef PS_LIB_TABLE_NAME