  J.C. Wren
  2007/07/09
  jcwren@jcwren.com

  The most recent version of this package may be found at http://jcwren.com/arm

Overview:

  This package demonstrates using LPCUSB and FatFS under FreeRTOS on the Olimex
  LPC2148 board, using GCC and newlib.  Examples include FreeRTOS queues and
  semaphores, LPC2148 analog to digital converters (ADCs), external interrupts,
  the real-time clock (RTC), general purpose IO (GPIO), serial ports (UARTs),
  and USB.   Also included is a newlib syscalls.c that almost completely
  implements all syscalls.c functions.

  The package (as built, .hex file included) presents the USB port as a virtual
  comm port.  The virtualized port is used to talk to the console command
  interpeter (CCI), that allows various functions to be exercised.
  Alternatively, the package can re-compiled to use UART0 as the console port. 

  If a GPS with NMEA output at 4800 baud is connected to UART1, one of the
  tasks will parse the NMEA input stream, and display a position report.  In
  addition, the RTC may be set from the GPS time/date.

  FatFS support is included, and the CCI has several Unix-y commands to
  manipulate files (mkfs, df, ls, mkdir, rmdir, rm, mv, cp, chmod, and sync).
  There is also a command that allows through-put testing on the MMC/SD card. 

  This package exists because I wanted to familiarize myself with the LPC2148,
  FreeRTOS, FatFS and LPCUSB for a personal project.  By slightly modifying the
  resulting framework, I was able to produce a package that others may possibly
  find useful.


Software tools:

  The package compiles using the arm-elf GCC package.  Gentoo users can
  install this by emerging the 'crossdev' package, then 'crossdev -t arm-elf'.
  Once the arm-elf verison of GCC is installed, the package can be rebuilt with
  'make'.    

  To program the board, the Philips LPC2000 Flash Utility v2.2.3 Windows tool
  was used.  There are Linux based tools for programming the LPC21xx parts, any
  of which support the LPC2148 should be suitable.  It may be normal, but I
  couldn't get the board to program at speeds other than 19200 and 38400.

  ProComm was used to talk to the console port on UART0, and HyperTerm to talk
  to the console port when using USB (Don't get me started on how crappy
  HyperTerm is.  I *DESPISE* this abortion, and figure that Hilgraeve must have
  pictures of Gates with a goat or something.  We can argue about MS quality
  all day long, but HT has all the "quality" of a 6 year olds first programming
  project in QBASIC.  The only reason it was used was because ProComm can't
  talk to COM18, which is what the virtual serial port appears as).

  If using the USB virtual comm port under Windows, the 'usbser.sys' and
  'usbser.inf' files may be needed.  Often, these files are already on the
  drive somewhere, and Start->Search->Files can be used to located them.  If
  not present, they are included in the ./Windows directory in the package.

  Under Linux, 'minicom' should be able to talk to both the serial port and the
  virtual comm port the USB port appears as.  Bertrik's wiki, located at
  "http://wiki.sikken.nl/index.php?title=LPCUSB", has a note about using LPCUSB
  under Linux.

  The default baud rate for UART0 is 115200.  The baud rate selected for the
  USB virtual comm port is irrelevant, and may be any speed.


Rebuilding it:

  Simply typing 'make' should build the entire package.  The FreeRTOS modules
  will emit several warnings about type punned references, which can (safely?)
  be ignored.  

  If you wish to use UART0 for the console port, edit ./monitor/monitor.c, jump
  to near line 938, and change the "#if 1' to '#if 0', then recompile.

  If you wish to change the baud rates for UART0 or UART1, edit ./main.c, jump
  to near line 62, and change the rates.  Any standard baud rate should produce
  usable results.

  'make clean' will clean the project, removing the ./*.hex, ./*.lst, ./*.map,
  ./*.elf files, and ./common/common.a, along with all *.o and .depend files in
  any sub-directories.

  'make tags' will rebuild the ctags file for 'vi' (and no doubt emacs, if
  you're one of "them").


Hardware (required and optional):

  Olimex LPC-P2148 board (required)
  USB cable (optional)
  Serial cable (optional)
  GPS with NMEA output and serial cable (optional)


Using it (Windows):

  For the purposes of these instructions, it will be assumed that COM1 is the
  serial port on the host PC, a USB cable is connected to the LPC-P2148 board
  and the PC, and that the Philips LPC2000 Flash Utility V2.2.3 will be used
  for programming.  Please note that Windows 2000 was used, and that dialogs
  for Windows XP are probably slightly different.  If you're using Vista, I'm
  surprised it can stay up long enough for you to read this document...

  Connect the RS232_0/ICSP DB-9 on the LPC-P2148 board to the comm port on the
  PC, using a straight-thru serial cable.  Set both the ICSP slide switches
  (located near the RS232_0/ICSP DB-9 connector) to the 'on' position (towards
  the DB-9 connector), then press the reset button (located next to the ICSP
  switches).  

  Configure the Philips utility for COM1, 38400 baud.  Click the 'Read Device
  ID' button.  LPC2148 should appear in the 'Device' text field.  Note that the
  device ID has to be read to set the value, as there's a nasty bug in the
  utility that prevents selecting it from the drop down list.

  Click the "..." button in the 'Flash Programming' block, then locate and
  select the 'lpc2148.hex' file, followed by clicking the 'Upload to Flash'
  button.  At this point, the flash image should start being programmed.

  When it completes, set the two ISCP slide switches to 'off', and press the
  reset button.  The 'LED1' LED should start flashing.  

  If Windows already does not already have the 'usbser.sys' driver installed, a
  dialog will appear regarding the discovery of new hardware.  (I don't
  remember how the dialog goes, so you'll have to infer your way through this
  process).  When prompted for the driver, navigate to the ./Windows directory,
  and select 'usbser.inf'.  This should install the driver for the virtual comm
  port that will support the USB port.

  Right-click on the 'My Computer' icon on the Windows desktop, select
  Properties, then the Hardware tab, followed by 'Device Manager'.  Click the
  '+' on the 'Ports (COM & LPT), and there should be an entry for "USB CDC
  serial port emulation (COMxx)" (where 'xx' will be a number).  Note the COM
  port for use with HyperTerm (see previous rant).
  
  Start HyperTerm (Start->Programs->Accessories->Communications->HyperTerm.
  When the dialog appears, type a name for the connection (The COMxx name is a
  good choice).  Click the drop-down box under 'Connect using'.  Select the
  COMxx port name from the drop-down list.  Click 'OK', followed by File->Save.
  Now click the third icon from the left, which looks like a telephone with the
  handset on the hook.

  If all went well, typing 'help<return>' should show a list of commands
  supported by the CCI.  If so, congratulations!  You can now play with various
  commands.  If not, there's not much advice that can be offered at this point.


Using it (Linux):

  Eeek!  This needs to be written.


Hardware thingies:

  The two push buttons on the LPC-P2148 board (B1 and B2) enable and disabled
  LED2.  Pressing B1 should light LED2, pressing B2 should extinguish it.
  These buttons are connected to the EINT2 and EINT0 lines, respectively.  The
  associated code demonstrates handling an external interrupt, and toggling an
  I/O pin in the interrupt service routine (ISR).

  The potentiometer, AN_TR, is connected to ADC0, channel 3.  The 'sensors'
  task checks the value every 100 milliseconds.  The software divides the pot
  into 4 zones, each covering about 1/4 of the range the pot may be rotated.
  When the pot is fully counter-clockwise, LED1 will be on for 200 milliseconds
  and off for 800.  When the pot is moved to the 2nd zone, the on/off times
  become 400ms/600ms.  The 3rd zone has on/off times of 600ms/400ms, and fully
  clockwise is 800ms on, 200ms off.

  LED1 is controlled by the LED task.  This is a lower priority task.  Each
  time a single on/off cycle has completed, it's message queue is checked to
  see if the blink ratio times should be changed due to the AN_TR pot changing
  zones.

  LED2 is controlled by the B1 and B2 push buttons, as mentioned above.


CCI commands:

  If you're a Linux user, most of the file commands are fairly self
  explanatory.  If you're not a Linux user, you should be, because it's better
  on our side of the fence.  The file commands require that a MMC/SD card be
  installed in the MMC/SD slot.  BEFORE USING THE FILE COMMANDS, USE THE
  'mount' COMMAND TO MOUNT THE MMC/SD CARD.  Note that the first partition on
  the MMC/SD card will be mounted, and this is the only one supported.  It must
  be a FAT12, FAT16 or FAT32 partition.

  If the MMC/SD card is not formatted with a FAT12/FAT16/FAT32 file system, you
  can use the 'mkfs' command to create it.  If anything already exists on the
  card, 'mkfs' will wipe it out.  

  Note that while a fairly good success rate has been obtained with the cards
  on hand, one Sandisk 64MB MMC card did not work.  Not sure why, but the MMC
  drivers are probably not handling something quite right.

  'cpcon <filename>' allows a text file to be created from the CCI.  Enter text
  until you're bored, then type ctrl-d save and exit.  Note that whatever
  characters are typed are saved into the file verbatim.  This means that
  characters like backspace are actually put into the file (feel free to
  improve that code...)

  Before creating any files, you may wish to set the system date, so that files
  are date/time stamped properly.  If a GPS with NMEA output is connected to
  RS232_1, you can use the 'gps' command to verify the serial connection, that
  NMEA data is being parsed, and that the GPS has acquired (required for the
  date/time to be set).  If you have no GPS attached, you may enter the date
  and time as parameters.  'settime 2007/07/08 22:51:25' will set the date and
  time to July 8th, 10:51pm and 25 seconds.  No timezone info is applied, so
  date/times acquired from the GPS are UTC.  Date/times set manually may be set
  to local time or UTC (or something completely random, if you're into that).

  The 'thruput' command allows measuring MMC/SD read and write performance.
  Eight file sizes are used: 1K, 8K, 16K, 64K, 128K, 512K, 1MB, and 2MB.  A
  temporary file is created on the MMC/SD card.  Measurements can be done one
  of four ways:  'noints' (fastest, but disables all tasking), 'normal' (CCI
  task priority is not changed, no tasks are suspended), 'suspendall' (all
  tasks are suspended, no context switches made, but 10ms interrupts still
  runs), and 'high' (CCI task is elevated to highest priority for duration of
  test).  Oddly, writes are faster than reads when not using the 'noints' mode.
  I have not yet researched why.  Leaving interrupts enabled *seriously*
  impacts the file system performance, nominally by a factor of 20.

  The 'date' command will report the current date/time from the RTC.  If you
  have an external 3V battery plugged into the BAT connector, the RTC will
  preserve it's values across power-downs.  Regardless of the battery presence,
  date/time will be preserved across resets (as long as power is not removed).

  The 'sensors' commands reports very little useful information.  The sensors
  task executes every 100ms, and samples the ADC connected to the AN_TR
  potentiometer.  Every time the task runs, the sensors counter is increment by
  one.  If the AN_TR pot is adjusted far enough to change the zone, the ADC
  changed value will increment.  See the section above on the pot.  The
  associated code demonstrates running a high priority task with a constant
  execution frequency, sampling an ADC, and sending a message to another task.

  The 'mem' command displays the various tasks running, and the amount of
  unused stack available to each task, along with the task priority and such.
  The associated code demonstrates the 'vTaskList' RTOS call.  Note that in a
  'real' system, leaving the task trace code enabled (configUSE_TRACE_FACILITY)
  imposes a slight penalty on context switches, which may be undesirable.
  

MMC/SD notes:

  As mentioned above, I have a Sandisk 64MB MMC card that the MMC drivers can't
  seem to recognize.  I have 4 other cards that work fine, one of which is an
  MMC, the other three which are SD.  I'd like to resolve this issue.  

  During the 'thruput' test, when interrupts are left enabled, I have on rare
  occasions seen a read or write error occur.  I believe this is because a
  context switch is taking place during some time critical code.  

  Ideally, interrupts would be disabled.  However, disabling interrupts makes
  an RTOS merely an OS.  The 'real-time' parts means predictable response to
  interrupts, and the executing time-critical tasks on-time.  In this code, the
  MMC/SD code is non-reentrant (only one task may read/write the card), and not
  time critical.   If multiple tasks have to write to disk, this would
  currently have to be handled by creating a task that communicates through
  queues to other tasks, and manages the MMC/SD card.

  Note that if a GPS is connected, a message that a NMEA checksum could not be
  found may occasionally appear.  While the actual test is being run, the GPS
  task is not processing messages, and the serial buffer overruns.  When the
  task is allowed to run again (between tests), partial NMEA messages that
  cannot be parsed may be present, resulting in the error message.


GCC notes:

  This code was compiled with -O3.  This results in code that's about 16K
  larger than -Os, but has a measurable impact on the MMC/SD card throughput
  (not large, but it can be seen).  I went with -O3 because with 512K of FLASH,
  and 144K or so used, there's plenty of room.

  I'm not sure what the compiliation options for newlib are.  'crossdev'
  compiled those, and I suspect it was with -Os, since embedded systems
  generally tend to consider size over speed.

  GCC is an amazing package.  I'm used to running into compiler issues with
  many of the micros that I work with (SCCS, Microchips C18, etc).  It's so
  nice to have a compiler that produces code without problems, and doesn't have
  idiot front-ends that can't even get the sign on an enum correct (at least
  Microchip got it right for the dsPIC and PIC24 parts, which used GCC.  C18...
  Don't go there...)

  There's a trick to writing Makefiles, and I don't have it.  It's an arcane
  art, and involves the slaughtering of goats, black candles, and full moons.
  The Makefiles I did write are very basic, and use recursion ('Recursive make
  considered harmful!'.  Foo on that.  Worked for me).  

  I tried a couple of approaches, and either everything built anyway, or
  nothing built at all.  To make the linking work, as files are compiled,
  they're dumped in to ./common/common.a, and main.c is linked against that.
  So far, the expected bite on the butt for doing it this way has not happened.

  It would be really neat to have Makefiles done right.  Alas, I don't know how
  to do it right.  So if the common.a approach looks really ugly to you, that
  means you probably know how to write Makefiles that handle sub-directories
  correctly, and you can tell me how it should be done :)  (With examples!)


Notes on newlib:

  I wasn't happy with the newlib syscalls.c that was included in the original
  LPC2148 port.  I more or less completely rewrote this, with the exception of
  _sbrk().  _open() can open the serial ports, USB port, and FatFS files.  All
  supporting functions except _fstat() work (see FatFS complaint at bottom).

  Newlibs method of converting a file descriptor (as returned by _open()) to a
  slot (which points to assorted info for that fd) uses a loop.  As this is
  done on EVERY read and write call, unnecessary overhead is added.  I fixed
  the find_slot() code to cache the last fd, and if it's the same on a
  subsequent call, the search is skipped.

  _open() is VERY suspect, in that remapping of FatFS f_open flags don't
  correspond cleanly to Unix's open() call.  I handle the four common cases
  correctly, but lesser used ones may result in a EINVAL errno on open.  

  Opening FatFS files is expensive, RAM space-wise.  Each open file uses a
  FatFS FIL structure which contains a 512 byte buffer, plus some additional
  space.  With 32K on a LPC2148, and 20K being used for the FreeRTOS heap, that
  leaves 12K that has to be used for the stack, heap, printf(), etc.  Don't go
  wild opening files, and be sure to close unused files to free the space.  Use
  open() instead of fopen() whenever possible, as the FILE structure has it's
  own set of buffers.

  There may be a way to figure out how much heap and stack have been used under
  newlib.  If there is, I haven't figured it out yet.  I'd really like to be
  able to make a newlib or system call that returns total space available, heap
  used and stack used. 

  Since stdout and stderr point to same place, it's wise to close stderr and
  set stderr to stdout.  Only functions like assert() use stderr, so
  intermixing stderr and stdout shouldn't be a problem.  Especially since
  there's no redirection of I/O...


Header file for LPC2148 (lpc210x.h):

  The original LPC2148 header file was very lacking.  Not only were individual
  bit fields generally not defined, major peripherials weren't defined.  As a
  result, FreeRTOS, LPCUSB, FatFS and newlib all used local defines.  Worse,
  some of these were simply "SOMEREG = (1<<31)".  Great.  What does bit 31 do?

  Personally, I feel the best way is to define structures AND #defines.  It's
  good that a structure has an element called 'CLK', but setting CLK to 0
  doesn't give a hint as to what clock mode is being set.  A #define for
  XXX_YYY_CLK_BIPHASE, then saying XXX_YYY_bits.ClkMode=XXX_YYY_CLK_BIPHASE is
  a lot clearer.

  I defined a mess of #defines, with the majority matching the names in the
  datasheet.  There were few that become triplely redundant, such as
  WD_WDFEED_WDFEED1.  This was reduced to WD_FEED_FEED1.  The characters prior
  to the first underscore define the module, with the next set the defining the
  register name.  Subsequent fields define the bit field name, and then
  possible variations.

  What I don't like about using #defines to define the registers is that the
  programmer needs to know if the bits being affected need to be AND'ed or
  OR'ed.  Structures neatly solve this problem, but defining all the structures
  take s alot of work (yea, IAR has already done that, but it's not legal to
  just swipe their nice headers).

  With one exception I'm aware of (in the TODO section), I rewrote all the code
  that sets registers to use the values in the lpc210x.h file.  

  While I doubt it makes the code more portable (will NXP change block
  addresses, but leave bits the same?  Probably not), it does make it more
  readable.  

  One of the last major areas to be completed is to pull the USB protocol
  engine #defines into lpc210x.h.  These are currently defined in one of the
  USB header files, and have poor name scoping (does "ACK_STAT" tell you what
  module or register it applies to?  No.)


Software notes:

  All copyrights are by their respective authors.  FreeRTOS is by Rich Barry.
  LPCUSB is by Bertrik Sikken.  FatFS is by ChaN, with sections by Joel
  Winarske.  Other sections of code may have come from the intarweb, and have
  respective copyrights, indicated or not.  Any code that I personally authored
  is free for public consumption, unemcumbered by any copyrights, etc (that
  crap is just too confusing.  BSD? LPGL? GPL3?  Who the hell knows...)

  I've re-formatted a good deal of code in LPCUSB and FatFS.  Some portions
  were re-written, others simply re-formatted to my coding style (which I
  jokingly refer to as JC1).  I have occasionally whacked comment blocks that I
  didn't really think indicated what the code did, or was redundant.  I
  probably whacked some text with copyrights in the process.  This in no way
  reflects an attempt to claim the work as my own, or to otherwise dishonor the
  original authors.  As Isaac Newton (more or less) said, "If I have seen a
  little further it is by standing on the shoulders of Giants."  Without the
  work of these most excellent people, this code would not exist.  

  Most of the reason for my re-formatting is my way of understanding the code,
  going through it section by section.  It's good because I have a better
  understanding of it, worse because it makes drop-in replacement with updates
  from the authors more difficult.

  The most affected area is the SPI handling in the FatFS code.  Originally
  named 'mm_llc_spi1.c', I felt this was not cleanly integrated, so I rewrote
  it.  Maybe it's not better, but it is different :)

  The FreeRTOS code is almost completely untouched, except for moving an #if
  around that allowed compiling the trace code (configUSE_TRACE_FACILITY)
  without requiring the task suspend code (INCLUDE_vTaskSuspend).  In the end,
  this was probably irrelevant, since I compiled the task suspend code in
  anyway.


Things I wish were different:

  A collection of random little thoughts of things I wish were different.
  These are just MY opinions, based on the way I do things.  It's not to say
  the original authors were wrong.  It's just the way I'd make things, if I
  were smart enough to write this stuff from scratch.  Most people probably
  shouldn't even read the following list...

  While FreeRTOS attempts to isolate the user from system data structures, it's
  a little *too* aggressive.  These typedef'ed structures should be in a header
  file, so applications can at least use sizeof() to help determine memory
  allocation.  Everything is done through recasted void* pointers.

  It would be neat if FreeRTOS had a xDelayTaskUntil() that also took one or
  more queues as a blocking item.  I want to run a task every 'n' milliseconds,
  but if something shows up in a queue, process it early.  Perhaps this could
  work like Unix's select().  Or perhaps a variadic function that takes
  xQueueHandles as parameters.

  I dont' care for FreeRTOS's use of portBLAH typedefs for portable types.  The
  world is pretty used to U8, U16, N32, and BOOL for unsigned char, unsigned
  short, signed int, etc.  FreeRTOS also seems to require declaring too many
  things as 'signed', which should be a default.  I'm sure this is done for
  portability, but I find the types are not as intuitive as they could be.  

  Another minor itch is that all function names and types start with 'x'.  I
  would have preferred 'freertos', or better, a user-definable one, via a
  #define macro.  I think programmers forget that their package may be
  integrated into a larger system, and while their naming convention works well
  for their purpose, it may not scale well.  FatFS and LPCUSB are guilty of
  this as well.

  FreeRTOS has a couple errors in several of the modules regarding type
  punning.  I understand what type punning is, but I don't know how to fix it
  safely.  Perhaps RB will fix those up in the next release.

  FatFS changes return types too often, particularly for errors.  There's the
  errors from the SPI routines, the MMC routines, the disk routines, and the
  top layer FatFS code.  There should be unified errors for everything, so that
  errors can be cleanly communicated up the stack.

  FatFS can't go from file descriptor to filename.  I haven't figured out a
  clean and reliable way to map a fd back to a filename (FatFS f_stat() needs a
  file name).  I thought about malloc()'ing space in the openFiles_t structure
  and copying the filename when the file is opened.  However, paths can get up
  to 128 characters, and only _fstat() needs that information.  This seems very
  wasteful.

  FatFS wants the user to provid the get_fattime() function.  FatFS should
  really have a file for locally provided functions.  It's already specific to
  the SPI or IDE port implementation.  As such, it should be stubbed out to
  return 0 if the function isn't provided, or allow the user to implement in
  the platform specific file (basically, an equivalent of syscalls.c, but
  internal to FatFS).

  FatFS has naming conventions that I don't like.  It exposes too many internal
  function names that should be declared static.  Structure names like 'FIL'
  are ambiguous, and too likely to collide with other libraries.  Functions
  should be preceed by the supporting module or library.  All FatFS functions
  should be in the form of fatfsOpen, fatfsClose, etc.  

  LPCUSB is not organized quite the way I'd do it.  The USB protocol engine
  defines need to have their names modified and moved into the lpc210x.h. 

  Newlib lacks certain calls on the ARM7 platform.  sync() and chmod() do not
  exist, while mkdir() does, but wit no corresponding _mkdir() support in
  syscalls.c.  Returning ENOSYS is easy enough, and doesn't take but a few
  instructions.  Providing support for a wider range of calls would be good,
  taking into mind things like FatFS that provide file system support, etc.


TODO:
  ./FreeRTOS/portable/GCC/ARM7_LPC2000/port.c uses local defines for timer control
  Finish rest of syscalls.c functions (fstat ())
  Some modules (USB) still have local #defines for hardware (protocol engine)
