четверг, 27 октября 2011 г.

LM3S9B92 and FreeRTOS example

Usual all developers starts with example of Web-server on FreeRTOS for this board. But always it does not work: Ethernet link is lost. How to cure it?

First, download last version of FreeRTOS (I tryed FreeRTOSv7.0.2.exe archive). Then unpack it. You can cut unnecessary folders from Demo folder: all except "Common" and "CORTEX_LM3Sxxxx_Eclipse".

Then download Yagarto GNU toolchain (I used yagarto-bu-2.21_gcc-4.6.0-c-c++_nl-1.19.0_gdb-7.2_eabi_20110429) and install it.

Then open main.c in "Demo\CORTEX_LM3Sxxxx_Eclipse\RTOSDemo" and change prvSetupHardware() function to:
void prvSetupHardware(void)
{
 SysCtlClockSet(SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ);
 SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
 GPIODirModeSet(GPIO_PORTF_BASE, (GPIO_PIN_2 | GPIO_PIN_3), GPIO_DIR_MODE_HW);
 GPIOPadConfigSet(GPIO_PORTF_BASE, (GPIO_PIN_2 | GPIO_PIN_3 ), GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD);
 vParTestInitialise();
}
After it call make in console (Makefile is near main.c :). And now program RTOSDemo.bin into your chip with LM Flash Programmer tool. MAC address of the device should be set. Now reboot MCU and try to ping it - default IP address is 172.25.218.19. You can set static IP of your PC to 172.25.218.10/255.255.0.0 for this reason. And don't forget to disconnect your WiFi :)

There are pong packets! Now try to open in the Web browser http://172.25.218.19 - page will be refresh after 1 second and tasks will be shown.
Thanks to and it's help here.

среда, 26 октября 2011 г.

Hanged LM3S9B92 board

After trying FreeRTOS example for LM3S9B92 my board seems "hanged" (dead) - no response over Ethernet, no adventure game :) And I get message "Error to initializing target".
Last was cured by several turning on/off USB connector. But no game... :) And Finder can not find my board's IP...
After opening Putty on virtual COM port (created after installation of FTDI drivers - I'm talking about Windows:) with baudrate 115200 and reseting board by button on the board, I see message:
Colossal Cave Adventure
-----------------------
Connect to either the USB virtual COM port or
telnet into the Ethernet port in order to play.

MAC Address Not Programmed!
Aha! I ran LM Flash Programmer and on "Other Utilities" tab and:
  1. Reset device by "Debug port unlock" feature (select "Tempest Class", click "Unlock" and follow instructions on message boxes)
  2. Switch to "MAC Address Mode" and programmed MAC address (it's possible to use FF-...-FF).
  3. Re-program device by original firmware (always save original firmwares!)
After this reseting device show in Putty session:
Colossal Cave Adventure
-----------------------
Connect to either the USB virtual COM port or
telnet into the Ethernet port in order to play.

IP: 169.254.3.0
Netmask: 255.255.0.0
Gateway: 0.0.0.0
...after "Wait..." and obtaining IP address. Finder found this IP address, and colossal game is working... over Ethernet :)

вторник, 25 октября 2011 г.

ypweb literate programming tool

After I tried LP technique, I decided that it help me to understand my code better and cuts many possible errors. But I need easier tool, lesser verbose... I implemented very lightweight Python 3 tool (about 20Kb) and called it ypweb. It's hosted on Google.
Main differences with other LP tools are:
  • produces only reStructuredText output
  • very lightweight (only one Python 3 file) about 20Kb
  • doesn't need comment line symbols for document strings (like #!) and code-chunks: only plain text
  • document and code context are switched by special line with short variants
  • generated index contains used by user (not predefined) classifiers
  • doesn't allow code-chunks "placeholders" (defining in one place/inserting in another)
  • supports any input and output charsets (see -h)
Short example:

  1 | Some definitions (macroses) used in COM module:
  2 | ;; x.h; defs; COM definitions
  3 | ;; Port number
  4 | #define PORT 1
  5 | ;; Baudrate
  6 | #define BAUD 9600
  7 | ;; funs; open()
  8 | int open(char *name, char *mode);
  9 | ;;
 10 | Another doc strings...
 11 | ;; x.c; funs; open()
 12 | code of open function here...
 13 | ;; x.h; defs; XXX
 14 | #define XXX
 15 | ;;
 16 | docs strings again...

Line 1 is the document chunk (file may starts with any chunk: doc or code). Line 2 is the special kind of line which switch context to code and begins with special marker (;;) and consists of 3 parts (may be lesser) splited by ;. Both symbols (;; and ;) may be changed to another in command line. It "says": next chunk is code, generates x.h file with some definitions ("defs" but may be any word preferred by user) and is the "COM definitions". These fields will be used also in index generating.

Line 3 is short form of switch-context-line (only caption, no file name or classifier). Line 4 is code and will be saved in the source file. Line 4 is like line 3, next is source line again...

Line 7 is short switch-context-line too and consists of classifier and caption, no filename, so will be saved in the same file - x.h.

Line 9 is empty switch-context-line, so it ends code chunk, nothing else. Next is always doc chunk.
Line 11 is switch-context-line which starts new source file: x.c. Line 13 begins code chunk for early created x.h file. Well, switch-context-line switch into code chunk and defines what is the code if not empty, empty - switches into doc chunk.

It's very clean and simple format. And is the reStructuredText too. So, you can use in it any kind of usual reSt markup!

After processing this file, .rst file and x.h, x.c will be generated. Also .rst file will have index section in the end with references to definitions of the code chunks.

понедельник, 10 октября 2011 г.

AVR timers: calculate prescalers

Functions below are only for Atmega128, see "bitness" of timers, prescalers values...

When you use AVR timers, you should setup it's prescalers' values. Often, programmers calculates prescaler on the paper and then hardcodes it into the code. And this is done every time for new delay value. This task can be done automatically by next algorithm. Next is the Python prototype of the algorithm.
class Timer:
    freq = 0 # freq. of timer
    bits = 0 # "bitsness" of timer

# We have for example 4 timers
_timers = [Timer(), Timer(), Timer(), Timer()]

def init_timers():
    # setup bitness of the timers
    global _timers
    _timers[0].bits = 256
    _timers[1].bits = 65536
    _timers[2].bits = 256
    _timers[3].bits = 65536

# for Atmega128
def _alarm_setup(timer, D):
    prescales0 = (1, 8, 32, 64, 128, 256, 1024,)
    prescales = (1, 8, 64, 256, 1024,)
    # base freq of timer, the same for all but is possible to specify differents
    freq = 8000000 # Freq. of MCU

    if timer == 0:
        psc = prescales0
    else:
        psc = prescales

    _timers[timer].freq = freq

    T = 1000000 * psc[-1] * _timers[timer].bits / freq
    cycles = D/T
    if cycles:
        D -= cycles*T

    for _psc in psc:
        # T - timer period (step in usec)
        T = 1000000 * _psc * _timers[timer].bits / freq
        # D_T - how many T (timer periods) are in D (delay)
        D_T = float(D)/T
        if D_T <= .5:
            # can not be rounded even to 1, too short delay time!
            return None
        elif D_T > _timers[timer].bits:
            # delay is too long for this prescale value
            continue
        else:
            # bingo!
            cn = _timers[timer].bits - int(D_T) + 1
            prescale = _psc
            return (cn, prescale, cycles)
    return None

# test
init_timers()
print _alarm_setup(0, 10000000)
print _alarm_setup(0, 256)

Function _alarm_setup() returns triplet (start value of timer counter, prescaler value, total cycles of the timer counter). These 3 values defines initial parameters of counter which should count to delay D microseconds. It's possible to define any values of delay time in this manner.
This Python prototype example is only to show idea of algorithm. But next is the real implementation on C for WinAVR:
/* Calculates prescale (divisor of timer: 1,8,...) and start
 * counter value and total cycles number. Returns 0 on success, -1 on faulire.
 * D is the delay in microseconds.  timer is number of timer.
 * Out values are saved in corresponding timerc_t.
 * Atmega128 implementation!!!
 */
int
_alarm_setup(int timer,
             unsigned long D)
{
        int i;
        int max_psc; // max. value of prescaler of timer
        int *psc; // prescalers of timer
        unsigned long T; // period of tick
        unsigned long Tclk; // period of clock
        unsigned long Tall; // period of timer cycle (from 0 to bits)

        psc = _timers[timer].prescalers;
        max_psc = psc[_timers[timer].nprescalers-1];

        /* Base frequency is F_CPU. Real frequency is F_CPU/prescaler.
           One tick occupes 1/freq seconds (freq in MHz). N ticks occupes
           N/freq. N is max ticks number in counter = bits of this counter =
           _timers[timer].bits. So, total time to count all ticks of counter is
           N/freq = N/(F_CPU/prescaler) = N*prescaler/F_CPU. Freq is in MHz, to
           use microseconds instead of seconds, * 1000000.

           T is the total time of count all the counter with slowest freq (with
           last prescaler - max_psc). cycles is how many counter cycles are in
           D with slowest prescaler on this timer-counter.

           Then D set to D without cycles time.
           */

        // 1000000 * max_psc > F_CPU, so T/F_CPU != 0
        T = (1000000 * max_psc / F_CPU) * _timers[timer].bits;
        _timers[timer].cycles = D/T;

        if (_timers[timer].cycles > 0) {
                D -= (_timers[timer].cycles) * T;
                _timers[timer].cycles_prescaler = max_psc;
        }
        else {
                // If does not need cycles, cycles_prescaler will be 0
                // (may be used as flag of this)
                _timers[timer].cycles_prescaler = 0;
        }

        D *= 1000; // in nanoseconds
        Tclk = 1000000000 / F_CPU; // in nanoseconds
        for (i=0; i<_timers[timer].nprescalers; i++) {
                T = Tclk * psc[i]; // time of one tick
                Tall = T * _timers[timer].bits; // time to count all ticks of counter
                if (D > Tall) {
                        // delay D is too long for this Tall
                        continue;
                }
                else {
                        _timers[timer].prescaler = psc[i];
                        // D/T how many ticks in D, cn is ticks from 0
                        _timers[timer].cn = _timers[timer].bits - D/T;
                        return (0);
                }
        }
        return (-1);
}

This function uses global array of timers: _timers. This is the array of the timerc_t structs:
typedef struct timerc_t {
        volatile timer_handler_t alarm_handler;
        volatile unsigned long nover; // number of overflow
        unsigned long bits; // number of bits
        volatile unsigned long cn; // start from this count value
        volatile unsigned long cycles; // cycles number
        volatile int prescaler; // prescaler (1, 8, 32... - depends on arch. and timer)
        volatile int cycles_prescaler; // prescaler (usually 1024) for total counter cycles
        int *prescalers; // array of timer-counter prescalers
        int nprescalers; // length of prescalers' array
} timerc_t; 
Full implementation of timers support for AVR (Atmega128 only at the moment) are here.