Sep 252010
 

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
}

Sep 232010
 
AKI-H8: Old but not forgotten

There is no actual use for it, but it promised back when I bought it, to be much fun. It is my only Ethernet connected microcontroller board (10BaseT only though, but still…) and the board comes with a large amount of RAM (2MB).

Since I nearly forgot how to use it, I better write this down here. I already have RedBoot installed (downloaded from here).

Connection details are: 38400 bps, 1 start and 1 stop bit, no flow control.

+DP83902A - eeprom ESA: 00:02:cb:01:a1:7d
... waiting for BOOTP information
Ethernet eth0: MAC address 00:02:cb:01:a1:7d
Can't get BOOTP info for device!

RedBoot(tm) bootstrap and debug environment [ROM]
Non-certified release, version UNKNOWN - built 21:28:57, Apr 11 2004

Platform: Akizuki H8/3068 Network micom (H8/300H)
Copyright (C) 2000, 2001, 2002, Red Hat, Inc.

RAM: 0x00400000-0x005f4000, [0x00400000-0x005e1000] available
FLASH: 0x00000000 - 0x00080000, 8 blocks of 0x00010000 bytes each.

To Set IP address:


RedBoot> ip_address -l 192.168.11.55/24 -h 192.168.11.53
IP: 192.168.11.55/255.255.255.0, Gateway: 0.0.0.0
Default server: 192.168.11.53

.53 is the tftp server to use later. .55 is the assigned IP address of the H8 board.

To load a file via tftp:

RedBoot> load lcd_clock.elf
Using default protocol (TFTP)
Entry point: 0x00400000, address range: 0x003fff8c-0x0040add0

The program is from http://uclinux.quake4.jp/uClinux/Chapter5/lcd_clock.elf. Then execute it via


RedBoot> exec 0x00400000
Now booting linux kernel:
Entry Address 0x00400000
Cmdline :

And on the LCD you should see a clock starting at 00:00:00, increasing 1 per second.

Notable issue: If the LCD shows nothing or the board does not power on, turn J1 (Vdd/Vss). Some LCD need one setting, some another one. The original display needs 1-3 and 2-4 connected, another display I have needs 1-2 and 3-4 connected.

And here the main program including how to set an interrupt vector:

#include 
#include 

#include "h8_sample.h"
#include "h8_lcd.h"

static unsigned char buffer[16] = "";
static int counter = 0;

static unsigned char hour = 0;
static unsigned char minute = 0;
static unsigned char sec = 0;

void Set_Vector( int num, void *vect )
{
	void **vvt;
	vvt = (void **)0x00FFFD20;
	void *jv = 0x5A000000 + vect;
	vvt[num] = jv;
}


//
// 8ビットタイマー初期化(100ms)
//
void Init_Timer8(void)
{
	T8TCR0.BIT.CKS   = 0;	// クロック一時停止
	T8TCR0.BIT.CMIEB = 0;	// CMFBによる割り込み禁止
	T8TCR0.BIT.CMIEA = 0;	// CMFAによる割り込み禁止
	T8TCR0.BIT.OVIE  = 0;	// OVFによる割り込み禁止
	T8TCR0.BIT.CCLR  = 1;	// コンペアマッチAでクリア
	
	T8TCR1.BIT.CKS   = 4;	// 8TCNT0コンペアマッチAでカウント
	T8TCR1.BIT.CMIEB = 0;	// CMFBによる割り込み禁止
	T8TCR1.BIT.CMIEA = 1;	// CMFAによる割り込み許可
	T8TCR1.BIT.OVIE  = 0;	// OVFによる割り込み禁止
	T8TCR1.BIT.CCLR  = 1;	// コンペアマッチAでクリア
	
	T8TCSR0.BYTE	 = 0;	// クリア
	T8TCSR1.BYTE	 = 0;	// クリア
	
	T8TCNT = 0;				// カウンタクリア
	T8TCORA0 = 249;			// 20,000,000 / 64 / 250 = 1250
	T8TCORA1 = 124;			// 1250 / 125 = 10Hz (100ms)
	
	T8TCR0.BIT.CKS	 = 2;	// 内部クロック20MHz φ/64
}


//
// 8ビットタイマーチャンネル0
// コンペアマッチA1/B1割り込み
//
#pragma interrupt
void int_cmiab1(void)
{
	T8TCSR1.BIT.CMFA = 0;	// コンペアマッチフラグAクリア
	counter++;
	if( counter > 9 ) {
		counter = 0;
		if( ++sec > 59 ) {
			sec = 0;
			if( ++minute > 59 ) {
				minute = 0;
				if( ++hour > 23 ) {
					hour = 0;
				}
			}
		}
	}
}


int main()
{
	Set_Vector( 38, int_cmiab1 );

	ABWCR.BYTE = 0xFF;	// バス8ビットモードに設定
	wait20us();
	
	P4DDR.BYTE = 0xFF;	// PORT4 = OUTPUT
	wait20us();
	
	P5DDR.BYTE = 0x00;	// PORT5下位4ビット入力
	wait20us();
	P5PCR.BYTE = 0x0F;	// プルアップ
	
	LCD_Init();
	
	hour = 0;
	minute = 0;
	sec = 0;
	counter = 0;
	Init_Timer8();
	
	_sti();				// 割り込み許可
	while(1) {
		int i;
		for( i = 0 ; i < 5 ; i++ ) {
			sprintf(buffer, "%02d:%02d:%02d" ,hour, minute, sec);
			LCD_Locate(0,0);
			LCD_Putstr(buffer);
			wait(100);
		}
		if( ! P5DR.BIT.B0 ) {
			if( ++hour > 23 ) hour = 0;
		}
		if( ! P5DR.BIT.B1 ) {
			if( ++minute > 59 ) minute = 0;
		}
		if( ! P5DR.BIT.B2 ) sec = 0;
		if( ! P5DR.BIT.B3 ) break;
	}
	return 0;
}

Sep 052010
 
Linear LED Fading

Using PWM to fade a LED in and out is dead-simple. Except that the brightness does not seem to change linearly: It gets bright very fast, and then it nearly does not change anymore.

The fix: linearize it.

Since floating point operations are not that popular on a low power microcontroller as the Arduino, the easiest way to do this is via a lookup table to map 8 bit values for bridgeness into PWM values to drive the LED.

Perl to the rescue!
perl -e 'for(my $i=0;$i<256;$i++){ print int(exp($i/46)),",";}'

Manually change the first one to 0 (0 intensity is supposed to be off).
And now LED fading is easy. The example below shows also how to use TimedAction Library which I personally found very useful if you want to do 2 things independently on the Arduino (in this case: blink one LED and fade another one)

#include 

/* pwm9

Fade pin on PIN9 up and down and blink LED13

The circuit:
* LED attached from digital pin 9 to Vcc.

*/

#define ledPWMPin 9    // LED connected to digital pin 9
#define ledBlinkPin 13 // LED PWM

static unsigned char exp_map[256]={
  0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,
  3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,5,5,5,
  5,5,5,5,5,6,6,6,6,6,6,6,7,7,7,7,7,7,8,8,8,8,8,8,9,9,
  9,9,10,10,10,10,10,11,11,11,11,12,12,12,13,13,13,13,
  14,14,14,15,15,15,16,16,16,17,17,18,18,18,19,19,20,
  20,20,21,21,22,22,23,23,24,24,25,26,26,27,27,28,29,
  29,30,31,31,32,33,33,34,35,36,36,37,38,39,40,41,42,
  42,43,44,45,46,47,48,50,51,52,53,54,55,57,58,59,60,
  62,63,64,66,67,69,70,72,74,75,77,79,80,82,84,86,88,
  90,91,94,96,98,100,102,104,107,109,111,114,116,119,
  122,124,127,130,133,136,139,142,145,148,151,155,158,
  161,165,169,172,176,180,184,188,192,196,201,205,210,
  214,219,224,229,234,239,244,250,255
};

TimedAction timedBlink=TimedAction(1000,blink);
TimedAction timedPWM=TimedAction(100,fade);

void setup()  {
  pinMode(ledBlinkPin,OUTPUT);
  pinMode(ledPWMPin,OUTPUT);
}
// loop() is always called again when it exists
void loop()  {
  timedBlink.check();
  timedPWM.check();
}
// Blinking on PIN13
void blink() {
  static int ledState=LOW;

  ledState ? ledState=LOW : ledState=HIGH;
  digitalWrite(ledBlinkPin,ledState);
}

// Fading on PIN9
void fade() {
  static int currentPWM=0;
  static int dir=1;

  // 0 is supposed to be dark
  // Since LED connects to 5V, 0 is bright, so invert
  analogWrite(ledPWMPin,255-exp_map[currentPWM]);
  currentPWM+=dir;
  if (currentPWM > 255 || currentPWM < 0) {
  currentPWM-=2*dir;
  dir = -dir;
  }
}