RX: H8 modernized

H8 evolved to H8S which evolved to H8SX which evolved into the RX line of Renesas. It’s not another RISC CPU, which usually would not matter at all as everyone uses C/C++ for programming microcontrollers (yes, I know, exceptions do exist), but for short code like the startup code, a little bit of assembler is still needed. Neither ARM nor MIPS nor SPARC assembler is fun to read or write.

Here some examples taken from a software I2C driver inspired from the I2C driver from MES:

C code:

union un_p6dr {                                         /* union P6DR   */
              unsigned char BYTE;                       /*  Byte Access */
              struct {                                  /*  Bit  Access */
                     unsigned char B7:1;                /*    Bit 7     */
                     unsigned char B6:1;                /*    Bit 6     */
                     unsigned char B5:1;                /*    Bit 5     */
                     unsigned char B4:1;                /*    Bit 4     */
                     unsigned char B3:1;                /*    Bit 3     */
                     unsigned char B2:1;                /*    Bit 2     */
                     unsigned char B1:1;                /*    Bit 1     */
                     unsigned char B0:1;                /*    Bit 0     */
                     }      BIT;
};
#define P6DDR   (*(volatile unsigned char   *)0xFEE005) /* P6DDR Address*/
#define P6DR    (*(volatile union  un_p6dr  *)0xFFFFD5) /* P6DR  Address*/

#define I2CDDR  P6DDR
#define SDA_MASK 0x01
#define SCL_MASK 0x02
#define SDA     P6DR.BIT.B0
#define SCL     P6DR.BIT.B1

void i2c_stop(void)
{
  I2CDDR=SDA_MASK|SCL_MASK;
  SDA=0;
  SCL=1;
  wait_us(4);
  SDA=1;
}

AVR (8 bit RISC):

i2c_stop:
        push r16
        push r17
/* prologue: function */
/* frame size = 0 */
        ldi r24,lo8(3)
        sts -8187,r24
        ldi r16,lo8(-43)
        ldi r17,hi8(-43)
        mov r30,r16
        mov r31,r17
        ld r24,Z
        andi r24,lo8(127)
        st Z,r24
        ld r24,Z
        ori r24,lo8(64)
        st Z,r24
        ldi r24,lo8(4)
        ldi r25,hi8(4)
        rcall wait_us
        mov r30,r16
        mov r31,r17
        ld r24,Z
        ori r24,lo8(-128)
        st Z,r24
/* epilogue start */
        pop r17
        pop r16
        ret

MIPS (32 bit):

i2c_stop:
        .set    nomips16
        .frame  $sp,24,$31              # vars= 0, regs= 2/0, args= 16, gp= 0
        .mask   0x80010000,-4
        .fmask  0x00000000,0
        .set    noreorder
        .set    nomacro

        addiu   $sp,$sp,-24
        li      $3,3
        li      $2,16711680                     # 0xff0000
        sw      $31,20($sp)
        sw      $16,16($sp)
        li      $16,16777216                    # 0x1000000
        sb      $3,-8187($2)
        lbu     $2,-43($16)
        li      $3,-2                   # 0xfffffffffffffffe
        and     $2,$2,$3
        sb      $2,-43($16)
        lbu     $3,-43($16)
        li      $4,4                    # 0x4
        ori     $3,$3,0x2
        sb      $3,-43($16)
        jal     wait_us
        nop

        lbu     $2,-43($16)
        nop
        ori     $2,$2,0x1
        sb      $2,-43($16)
        lw      $31,20($sp)
        lw      $16,16($sp)
        j       $31
        addiu   $sp,$sp,24

H8/300H (16 bit):

_i2c_stop:
        mov.w   r6,@-r7
        mov.w   r7,r6
        mov.w   r4,@-r7
        mov.b   #3,r2l
        mov.b   r2l,@-8187:16
        mov.w   #-43,r4
        bclr    #0,@r4
        bset    #1,@r4
        mov.w   #4,r0
        jsr     @_wait_us
        bset    #0,@r4
        mov.w   @r7+,r4
        mov.w   @r7+,r6
        rts

RX (16/32 bit):

_i2c_stop:
        push.l  r7
        mov.L   #0xfee005, r14
        mov.L   #0xffffd5, r7
        mov.B   #3, [r14]
        mov.B   [r7], r14
        mov.L   #4, r1
        bclr    #7, r14
        mov.B   r14, [r7]
        mov.B   [r7], r14
        bset    #6, r14
        mov.B   r14, [r7]
        bsr     _wait_us
        mov.B   [r7], r14
        bset    #7, r14
        mov.B   r14, [r7]
        rtsd    #4, r7-r7

x86_64 (64 bit):

i2c_stop:
        .cfi_startproc
        subq    $8, %rsp
        .cfi_def_cfa_offset 16
        movb    $3, 16703493
        movzbl  16777173, %eax
        movl    $4, %edi
        andl    $127, %eax
        movb    %al, 16777173
        movzbl  16777173, %eax
        orl     $64, %eax
        movb    %al, 16777173
        call    wait_us
        movzbl  16777173, %eax
        orl     $-128, %eax
        movb    %al, 16777173
        addq    $8, %rsp
        ret

Easy to see why C wins this. ARM is not too bad too for a RISC CPU, but I have no example available. A notable oddity is that RX reversed bits (7,6 instead of 0,1). Not sure this is a bug or a feature.

Some more examples can be seen in the “99 bottles of beer” program examples under “A” like “assembler”.

It’s funny what makes one pick a microcontroller CPU. Since I don’t need performance or price for 1000 units, I can pick which assembler code looks easiest or nicest to me.
H8 and RX look like something readable and memorizable. In fact, H8 looks like Motorola M68k assembler. Both are said to be DEC PDP-11 related (see here and here)

Now this RX62N demo board is packed with interesting things and the price (US$99) is hard to beat. It also runs FreeRTOS since version 6.1, and Ethernet works too, which I have not yet working on my AKI-H8 board. And s JTAG based debugger is on-board too. And a graphics LCD. I think it’s a bargain similar to the STM32VLDiscovery or the STM8SDiscovery for each US$11.

Now let’s see how long Digikey takes to deliver them to Japan.

Update: 4 days.

 

The guys at KPIT Cummins provide a well working GCC tool chain for all kind of Renesas CPUs. Takes a lot out of the pain of using those.

For the longest time I used the Linux 10.02 GCC chain for H8. Worked right from the start. Yesterday I thought about updating to 10.03. Should be no problem. So as usual this is what I did:

  1. get the Linux (32 bit) RPM from their site
  2. alien -t gnuh8300_v10.03_elf-1-1.i386.rpm
  3. tar  -x  -v -C / -f gnuh8300_v10.03_elf-1.tgz

Then change my PATH to include the resulting /usr/share/gnuh8300_v10.03_elf-1/bin directory, and then…cc1 failed with libelf.so.1 missing:

/usr/share/gnuh8300_v10.03_elf-1/libexec/gcc/h8300-elf/4.5-GNUH8_v10.03/cc1: error while loading shared libraries: libelf.so.1: cannot open shared object file: No such file or directory

and

harald@v3k7$ ldd
/usr/share/gnuh8300_v10.03_elf-1/libexec/gcc/h8300-elf/4.5-GNUH8_v10.03/cc1
         linux-gate.so.1 =>  (0xf77ca000)
         libdl.so.2 => /lib32/libdl.so.2 (0xf77a4000)
         libelf.so.1 => not found
         libc.so.6 => /lib32/libc.so.6 (0xf7649000)
         /lib/ld-linux.so.2 (0xf77cb000)


Since this is a 32 bit compiler chain and you can see above and below:

harald@v3k7$ file /usr/share/gnuh8300_v10.03_elf-1/bin/h8300-elf-gcc
/usr/share/gnuh8300_v10.03_elf-1/bin/h8300-elf-gcc: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.9, not stripped


the library should be in /lib32/, but although I have ia32-libs installed, there is no /lib32/libelf* at all.
The fix is as simple as can be: get a working libelf.so.1 into /lib32/:

cd /tmp
wget http://ftp.jaist.ac.jp/pub/Linux/ubuntu//pool/main/e/elfutils/libelf1_0.147-2_i386.deb
alien -t libelf1_0.147-2_i386.deb
sudo cp usr/lib/libelf-0.147.so /lib32/
cd /lib32
sudo ln -s libelf-0.147.so libelf.so.1

That adds a 32 bit libelf into /lib32. Now cc1 is happy again:

harald@v3k7$ ldd /usr/share/gnuh8300_v10.03_elf-1/libexec/gcc/h8300-elf/4.5-GNUH8_v10.03/cc1
         linux-gate.so.1 =>  (0xf7784000)
         libdl.so.2 => /lib32/libdl.so.2 (0xf775e000)
         libelf.so.1 => /lib32/libelf.so.1 (0xf7748000)
         libc.so.6 => /lib32/libc.so.6 (0xf75ed000)
         /lib/ld-linux.so.2 (0xf7785000)

 
Aki-H8 - What Works

This weekend was surprisingly successful. Here the list of things working:

  1. LCD output. I finally got the timing right: 37μs after E went low you can send another command. Clear and Home command take 1.52ms
  2. Output on Port A and B (with the exception of PB.4 which is used for /CAS for the 16MBit DRAM
  3. SPI using a HC595 (8-bit serial-in, serial or parallel-out shift register with output latches)
  4. I2C using PB.0/PB.2 for PCF8574A (8 bit quasi-bidirectional I2C port expander)
  5. I2C using P6.0/P6.1 for PCF8574A (addr 0×70) as well as 24LC256 (addr 0xA0)
  6. I2C scanning
  7. 24LC256 EEPROM reading/writing
  8. PWM using 16-bit timer ITU1 for dimming a LED
  9. Scheduling regular tasks (a la TimedAction from Arduino), which allows to run a function in regular intervals (e.g. once per second, or every 50ms, down to 1ms resolution). Not as nice as full multitasking, but it makes unrelated tasks so much easier to run.

Regarding this ‘task scheduler’, here how to use it:

initTasks();
createTasks(0, 50, knight_rider);
createTasks(2, 700, led2_blink);
createTasks(3, 5, check_key);
createTasks(4, 1000, display_something);
wait(500);
createTasks(1, 1000, eeprom);

while(!global_exit) {
  checkTasks();
}

What is does is call knight_rider() every 50ms, call led2_blink() every 700ms etc.

As an example of one of those functions:

void led2_blink(void)
{
  static int led2=1;

  LCD.BIT.LED2=led2;
  led2=!led2;
}

Next step planned: FreeRTOS port. 2 reasons:

  1. There already is a H8S port (H8S is the successor of H8/300H)
  2. There’s a TCP/IP stack for FreeRTOS available (actually several, one of them uIP and lwIP), and some of those support RTL8019AS too

Choices I dropped:

  1. eCOS. RedBoot is great and it works as a great bootloader, but it needs an old GCC tool chain and it has odd boundary requirements. The gcc toolchain I use currently just works too well to drop it.
  2. NuttX. I like it, but no RTL8019AS support and I just don’t understand how to port it to the H8/300H.
  3. MES is originally the OS running on the AKI-H8 board(s), but it depends on an old gcc tool chain and is no longer developed. MES2 only runs on more recent CPUs (SuperH and ARM). It would also not allow me to keep on using RedBoot.
 
AKI-H8: RedBoot

RedBoot is what is installed on the AKI-H8 board I have. I put it there myself, taking the image from http://sourceforge.jp/projects/ecos-h8/ . It can configure its startup behaviour as I know from several routers which use RedBoot. But I’ve never done that. So far no need, but recently I use that board a lot as it has lots of memory and loading a file via network beats XModem upload. But when you want to boot off the microcontroller without a network connection… Time to figure out how RedBoot handles the FLASH memory.

The first test was using fconfig, which is supposed to configure RedBoot:

RedBoot> fconfig -i
Initialize non-volatile configuration - continue (y/n)? y
Run script at boot: false
Use BOOTP for network configuration: false
Gateway IP address: 192.168.11.1
Local IP address: 192.168.11.55
Local IP address mask: 255.255.255.0
Default server IP address: 192.168.11.53
GDB connection port: 9000
Force console for special debug messages: false
linux boot command:
Network debug at boot time: false
Default network device: dp83902a_eth0
Update RedBoot non-volatile configuration - continue (y/n)? y


Looked good! But then:

... Erase from 0x00070000-0x00080000:
Error erasing FIS directory at 0x00070000: Device/region is write-protected

Well, it’s not that easy it seems. Turns out 2 things are needed first:

  1. Make the flash not read-only (DIP switch 4 to on I think)
  2. fis init -f to initialize flash

Afterwards:

RedBoot> fis init -f
About to initialize [format] FLASH image system - continue (y/n)? y
*** Initialize FLASH Image System
... Erase from 0x00020000-0x00070000: .....
... Erase from 0x00080000-0x00080000:
... Erase from 0x00070000-0x00080000: .
... Program from 0x005e4000-0x005f4000 at 0x00070000: .

to initialize flash. And then change the boot up configuration to configure the IP address to the one I like:

RedBoot> fconfig
Run script at boot: false
Use BOOTP for network configuration: false
Gateway IP address: 192.168.11.1
Local IP address: 192.168.11.55
Local IP address mask: 255.255.255.0
Default server IP address: 192.168.11.53
GDB connection port: 9000
Force console for special debug messages: false
linux boot command:
Network debug at boot time: false
Default network device: dp83902a_eth0
Update RedBoot non-volatile configuration - continue (y/n)? y
... Erase from 0x00070000-0x00080000: .
... Program from 0x005e4000-0x005f4000 at 0x00070000: .

This sets its own IP address to 192.168.11.55/24 and the TFTP server where to get its programs from to 192.168.11.53. I could even run a script (which is not more than commands I’d otherwise enter manually) at boot time and load a program from the TFTP server or from flash and execute it. See here for examples. I seriously start to like RedBoot. At least if you have plenty of FLASH and a network connection.

 

I figured out how to let a 16 bit timer of the H8/3069R (that’s the CPU on that board) run in free counting mode which is useful for timing. It runs at 20MHz/8=2.5MHz which reaches 25000 in 10ms. Turns out that a loop like:


for (i=0; i<10000; ++i) { _nop(); };

takes quite exactly 10ms. That would be 20 clock cycles per loop which sounds about right.

Anyway, what I did is:

  • Run above loop and check the counter: 25010 was the counter in the timer register
  • Run above code with 1k interrupt/s: 25392 was the result
  • Run above code with 1k interrupt/s and stack in internal RAM: 25332
  • Run it again with 10k interrupt/s: 29487
  • Run it again with 10k interrupt/s and stack in internal RAM: 28687

What does that mean: The CPU slows down due to interrupts about 1.5% if it has 1k interrupt/s and about 18% for 10k interrupt/s (resp. 1.3% and 14% if the stack is in the faster internal 16 bit RAM).

Compare this with the LPC2148 where it slows down only about 3.4% at 10k interrupt/s. Quite a difference. Given the age of the H8 CPU though, I think it's reasonable enough. Also note that the 2MB memory is connected via an 8 bit memory bus compared to the 32 bit internal FLASH/RAM bus of the LPC2148.

Here the code to initialize the 16 bit timer into free running mode:

void Init_Timer16_0(void)
{
  T16TCNT0=1;
  GRA0=0xFFFF;
  T16TCR0=0x23; // Clear on Match GRA, internal clock: phi/8
  TISRA=0; // No interrupts
  TMDR=0; // No PWM mode
  TSNC=0; // All independant
  TSTR=1; // Start Timer 0
}

 
4 Pin PWM Fan

I was looking for something fan-like to move some air around, specifically from under my desk at work as it gets too warm there. It’s nice in winter, but unwanted in summer.

I was looking into this which needed a 50 Euro power control module and of course a propeller. And it would create about 100W output. Cool stuff, but overkill. Of course a simple small fan for 1000 Yen would do the trick, but where is the fun in that.

In the end I found this most simple method: a normal 4 pin PWM controlled fan as computers use them. Needs 12V DC, returns 2 count/revolution and can be controlled via a simple 5V signal. Can be easily controlled by an Arduino, and it can be programmed as I like (faster/slower, depending on time, temperature). Sounds like fun and useful at the same time!

Now let’s see if I can assemble it before it gets winter…

 
XBee - API Mode

After playing a bit in the transparent (AKA AT) mode, it became apparent that it’s quite limited if you plan to do more than just using 2 XBee’s as a wireless serial connection. E.g. it’s not possible to receive the state of the digital and analog inputs from a remote XBee endpoint. The biggest drawback of the API mode is that it’s quite difficult to interactively use it. It’s made for programs to use, not for humans.

After looking for a usable API library, I found this blog which not only pointed me to the right direction, but also to a Python library which is easy enough to use. Easy enough for me who’s not used to Python.

Here a short program included in the library and meant as a sample, which I I slightly modified to make D4 of the endpoint blink, and it sends back the status of D1 and D2 once in 0xf000ms. That part does not work though. I always seem to get the same values back regardless of the I/O status.

from xbee_api import *

class myXbeeApi(XbeeApi):
def onData(self,pkg):
#get header for IO data
if pkg["code"]==0x92:
  print "Samples %s-> D:%s/%s" % (pkg["data"]["mac"],pkg["data"]["dmask"],pkg["data"]["dsamples"])

api=myXbeeApi("/dev/ttyUSB1",9600)

device={
 "CO3":[0x00,0x13,0xa2,0x00,0x40,0x52,0x8d,0x8a],
  "EP1":[0x00,0x13,0xa2,0x00,0x40,0x4a,0x61,0x84]
}

led=False

api.sendRemoteAT(device["EP1"],"D2",[0x02])
api.sendRemoteAT(device["EP1"],"D1",[0x03])
api.sendRemoteAT(device["EP1"],"IR",[0xf0,0x0])
api.sendRemoteAT(device["EP1"],"IC",[0x00])

while 1:

 #set led status
 led=not led
 if led:
  api.sendRemoteAT(device["EP1"],"D4",[0x04])
 else:
  api.sendRemoteAT(device["EP1"],"D4",[0x05])
 time.sleep(0.5)

Several things I learned while using those XBee radios:

  1. When flashing new firmware on the XBee using the X-CTU program, keep 9600 baud. It makes your life easier as it will always default back to 9600 which is when you will lose your connection to it again and again. When everything is set and working, change baud rate to what you like.
  2. Digi’s documentation is not bad, but more examples would make life easier. Luckily those XBees are popular enough that there are lots of examples in the wild.
  3. I still have no idea what the firmwares for digital and analog endpoints do. The endpoint with API interface seems to be able to handle everything.
  4. Watch out for sleep mode. For endpoints, you cannot turn off sleep mode. Instead use Pin 9 and set it to GND to disable sleep (and SM=1).
  5. Connect the RSSI and Associate pin to LEDs. Helps a lot while debugging.
  6. Have the Commission pin connected. It turns the radio on for 30s so sleep mode is not an issue for 30 seconds.
 
FTDI245

While browsing the web page of my favourite electronics shop in Akihabara Akizukidenshi (秋月電子) I saw this small USB module. Originally to connect things like FPGAs, microcontroller etc. which cannot use serial ports, it also has a bit-bang mode where it simply outputs on 8 data ports whatever you like. There’s a simple to use library available libftdi which can make those chip and its port directly accessible in Linux (and more).

The data sheet for that chip is at best spotty, but the chip works as advertised.

Some highlights of the FTDI 245RL and the above module in particular:

  • 8 data ports
  • I/O can be 3.3V or 5V
  • each I/O pin can be set to input or output independantly
  • Has a 3.3V step-down converter already built in
  • Can output 1MByte/second
  • Has an unique ID burnt into the chip
  • Can source and sink 2mA normally, or 3 resp. 8mA when in high-drive mode
  • 1 kb EEPROM is built in too

Quite versatile. Combine with a small Linux host (like this which I happen to have) and for many applications which need network and some I/O, this is an easier way to get things done compared with a stand-along microcontroller. As long as weight/power consumption and lack of low-latency (millisecond range or faster) is no issue, it’s at least easier to get started and you can use all the amenities of Linux (free choice of programming language, Internet connectivity, a clock, daemons for cron and at etc).

 
I2C Port Expander

Finally I had a bit time to play with my Propeller board I got sitting around for half  a year now. I wish it had more I/O ports, but with an “Remote 8-bit I/O expander for I2C-bus” this is a solvable problem. Only got to write a driver for it.

Which turns out to be far easier than I thought.

Here is the driver program. All of it. It’s using an I2C driver but that one is surprisingly simple too.

OBJ
i2cObject         : “Basic_I2C_Driver”

PUB WritePort(i2cSCL,_deviceAddress,i2cData)
i2cObject.Start (i2cSCL)
i2cObject.Write (i2cSCL,_deviceAddress | 0)
i2cObject.Write (i2cSCL, i2cData)
i2cObject.Stop(i2cSCL)

PUB ReadPort(i2cSCL,_deviceAddress) : i2cData
i2cObject.Start (i2cSCL)
i2cObject.Write (i2cSCL,_deviceAddress | 1)
i2cData := i2cObject.Read(i2cSCL,i2cObject#NAK)
i2cObject.Stop(i2cSCL)
return i2cData

And now to use it:

‘ setup i2cobject
i2cObject.Initialize(i2cSCL)

PCF8574AObject.WritePort(i2cSCL,PCF8574A_Addr,%1111_0000)

That will lit LED 0-3 and turn LED 4-7 off. Simple eh? And worked on the first try!

NuttX RTOS

 Uncategorized  4 Responses »
May 062009
 
NuttX RTOS

NuttX is yet another small RTOS for microcontrollers. Works best on not-so-small ones (128kB FLASH, 16kB RAM). LPC2148 suits this very well.

What attracted me to it was the list of ports, one example program (nsh which is a small shell, which is great for interactively testing), and the existence of a graphics library and the great support from Greg Nutt, the main developer.

Time from reporting a bug to fixing it: less then 2h. Take that, Sun and Veritas!

© 2011 Harald's Random Stuff Suffusion theme by Sayontan Sinha