Boa5200 HOWTO

From HW wiki
Jump to: navigation, search

Introduction

This document describes how to install and setup Linux and development environment for BOA5200 board. Assume that you have a development machine (your PC) that you use for development and building your applications which you consequently want to get running and test on BOA5200.

Serial line setting

The easiest way to communicate with the board ,when there is no OS and remote shell running on it, is over serial line. Recommended serial communication program is minicom. Setup minicom as follows:

Baud Rate – 38400

Bits - 8

Parity – N

Stop Bits - 1

Hardware Flow Control:- No

Software Flow Control:- No

After the setup you will see Redboot> command prompt. Here you can enter Redboot`s commands. Redboot is a simple boot manager bulit upon eCos real-time OS. For more details , see http://ecos.sourceware.org/ecos/docs-latest/redboot/redboot-guide.html.

IP address setting in Redboot

You can set ip address in Redboot using command ip_address instead of obtaing it from DHCP server(see next section).

ip_address [-b] [-l] local_IP_address  [/netmask_length] ] [-h  server_IP_address] [-d DNS_server_IP_address]

Example:

ip_address -l 192.168.100.1/24 -h 192.168.100.2

DHCP server setup

Redboot supports BOOTP protocol which means that it is able to get network information (IP,netmask,gateway IP address,etc.) from DHCP server (provides BOOTP besides DHCP protocol).

If you do not have a DHCP server on you network, you can install one on your development box: (on debian: apt-get install dhcpd) on your development machine. Example of my dhcp configuration file /etc/dhcpd.conf:

# I have two ethernet interfaces: 
# eth0 - Internet
# eth1 - connection to BOA5200 (IP= 192.168.10.1)
# I do not want to progate infos to 147.32.0.0 subnetwork
subnet 147.32.0.0 netmask 255.255.0.0 {
}

# private subnetwork
subnet 192.168.10.0 netmask 255.255.255.0 {
 option broadcast-address 192.168.10.255;
 option routers 192.168.10.1;
 option subnet-mask 255.255.255.0;
 default-lease-time 600;
 max-lease-time 7200;

# settings for BOA5200
 host BOA5200 {
  hardware ethernet 00:08:f1:11:22:33;
  fixed-address 192.168.10.2;
 }
}


Start dhcp server and reboot the board. After booting it has assigned IP, netmask and gateway address:

+PHY0: AMD AM79C874
FEC eth0: 100Mb/Full Duplex
Ethernet eth0: MAC address 00:08:f1:11:22:33
IP: 192.168.10.2/255.255.255.0, Gateway: 192.168.10.1
Default server: 192.168.10.1

TFTP server setup

Redboot is able to load file from remote tftp server into memory. Tftp server is lanuched by inetd daemon when a new connection comes. Therefore add the following line into /etc/inetd.conf :

tftp            dgram   udp     wait    nobody  /usr/sbin/tcpd  /usr/sbin/in.tftpd

Default tftp root directory is /tftpboot. You can change it by calling in.tftpd with specified directory as a parameter.

Alternative way for Ubuntu based distro

1. Install tftpd and related packages.

sudo apt-get install xinetd tftpd tftp

2. Create /etc/xinetd.d/tftp and put this entry:

service tftp
{
protocol        = udp
port            = 69
socket_type     = dgram
wait            = yes
user            = nobody
server          = /usr/sbin/in.tftpd
server_args     = /tftpboot
disable         = no
}

3. Make /tftpboot directory

sudo mkdir /tftpboot
sudo chmod -R 777 /tftpboot
sudo chown -R nobody /tftpboot

4. Start tftpd through xinetd

sudo /etc/init.d/xinetd start

see [Installing and setting TFTPD in Ubuntu]

Tool chain

Toolchain(gcc, ld, ...) for MPC5200 can be downloaded from ftp://rtime.felk.cvut.cz/MPC5200/gcc-powerpc-603e-linux-gnu-4.1.1-bin.tar.gz Unpack the archive:

cd /
tar xvzf gcc-powerpc-603e-linux-gnu-4.1.1-bin.tar.gz

You can also create a debian package from archive and then install the package:

alien --to-deb gcc-powerpc-603e-linux-gnu-4.1.1-bin.tar.gz

Note: If you are not root, use fakeroot to run the command.

Getting the kernel

Linux kernel sources patched for the board are maintained in a separate git tree. Use

 git clone git://rtime.felk.cvut.cz/boa5200/linux.git linux-boa5200

to download it.

You can also download the default kernel .config.

Building kernel

The simples way to build the kernel is putting the .config file (see the previous section) to the directory with sources and running:

make ARCH=ppc CROSS_COMPILE=powerpc-linux-gnu-

If you want to change configuration (.config) run:

make ARCH=ppc CROSS_COMPILE=powerpc-linux-gnu- menuconfig

After compilation a built image is placed into arch/ppc/boot/image directory.

The following commnad will install modules into <directory>/lib/modules/...

make INSTALL_MOD_PATH=<directory> modules_install   

Recommendation:

Instead of building the kernel in the sources directory, we recommend using of a separate build directory:

1. Make the build directory under the linux sources

mkdir _build
cd _build

2. Put the default .config and GNUmakefile into this directory

3. Optionally update the kernel configuration

make menuconfig 

kernel config file (.config) will be updated

Next time, always run make menuconfig from the _build directory

4. Compile the kenrel and install modules

make && make modules_install

If you often forget to switch to the build directory and run make in the source directory, put the following GNUmakefile into your source directory:

ifeq ($(O),)
$(error Please, run make in a different build directory (or use O= option))
else
include Makefile
endif

Updating RedBoot

You need to update RedBoot in order to boot Linux 2.6 kernel.

Download ftp://rtime.felk.cvut.cz/MPC5200/MPC5200-2007.02.01-redbootROMRAM.srec

!!! Warning: File names are case-sensitive !!!

# load RedBoot image from tftp server into memory at the address 0x100000
RedBoot>lo -b 0x100000 MPC5200-2007.02.01-redbootROMRAM.srec

!!! Warning: File names are case-sensitive !!!

# write image in flash memory
RedBoot>fi cr RedBoot
RedBoot>reset

If upgrade fails you can fallback to ROM Redboot image by typing 'A&M:'

If image of ROMRAM version of RedBoot with name "RedBoot" (case sensitive!!) is not found in FLASH minimal version of ROM RedBoot is started. This version does not support many services like TFTP protocol and FLASH management. To download ROMRAM version of RedBoot to FLASH it is necessary to follow these steps:

Load RAM version of RedBoot to BOA using xmodem (the image file MPC5200-2006.05.10-redbootRAM.srec is placed on BOA original CD):

RedBoot> lo -m xmodem

When finished RedBoot should answer with something like that:

CEntry point: 0x00080100, address range: 0x00080000-0x000bea04
xyzModem - CRC mode, 5763(SOH)/0(STX)/0(CAN) packets, 1 retries

Then start the RedBoot:

RedBoot> go

RAM RedBoot should start now. Download the new version of ROMRAM RedBoot to FLASH according to the steps above.

Loading kernel

Place the compiled kernel to the tftpboot directory. Then you can test your new image on the board as follows:

# load kernel image from tftp server into memory
  RedBoot> load zImage.elf

# execute image; root directory (/) is on flash memory
  RedBoot> exec

If you want to load the kernel from different TFTP server than the one provided by DHCP, you can use the following command to set the IP address of your server:

  RedBoot> ip_address -h 147.32.86.<xxx>

CAUTION: you must boot the kernel by RedBoot release at least 2007_02_01 otherwise it will not run! So you must load into RAM and then run the appropriate RedBoot image (or replace/update its image on flash with the new one - see the next section) and after then you can execute kernel image.

To write the loaded kernel to FLASH memory, execute command fis create: Example:

   RedBoot> fis cr Linux -b 0x00800000 -r 0x00100000 -e 0x00100000 -l 0x116000

To load the kernel from the FLASH are later, execute

   RedBoot> fis load Linux

(Then, you can perform exec -c "..." cmd.)

To find out paramter values execute fis list.

NFS-root setup

During the development phase of application it must be tested many times. However, it is annoying to copy several application files to flash memory every time. The practical solution is to mount via NFS working directory or whole root directory from the point of OS running on the board.

You can download already prepared root directory from ftp://rtime.felk.cvut.cz/MPC5200/MPC5200_root_070321.tar.gz

To export /var/MPC5200_root directory on your PC via NFS add the following line to /etc/exports:

/var/MPC5200_root 192.168.10.0/255.255.255.0(rw,sync,no_root_squash)

Then run command "exportfs -ra" so that the change take an effect.

If you want MPC5200 to be mount as root directory instead of that one in flash memory:

# load kernel image from tftp server into memory
 RedBoot> load zImage.elf
# execute kernel image with information where to 
# find root directory in parameter string
 RedBoot> ex -c "root=/dev/nfs rw nfsroot=192.168.10.1:/var/MPC5200_root ip=dhcp"

To mount another directory from Boa use this command:

mount -t nfs <ip>:/path/to/exported/dir /path/on/boa

NOTE: exportfs is a part of knfs (Ubuntu) or nfs-kernel-server (Debian) package.

Updating root filesystem on BOA

You can download already prepared root directory from ftp://rtime.felk.cvut.cz/MPC5200/MPC5200_root_070321.tar.gz

Create jffs2 image:

mkfs.jffs2 -r MPC5200_root -o jffs2.img -b -e 0x10000

On BOA:

Delete old image:

fis delete jffs2

Fill memory area at address 0x100000 of size 0xD00000 (size of root image + free space wanted) using mfill command:

mfi -b 0x100000 -l 0xD00000 -p 0xffffffff

Load root image to that memory area:

load -r -b 0x100000 jffs2.img

Write image to flash:

fis cr -b 0x100000 jffs2 -l 0xD00000

Root filesystem is mounted as read-only in Linux. To enable writting:

mount -o remount,rw /

--Molnam1 17:35, 15 December 2008 (CET)

Remark: I have been unsuccessful doing these steps, maybe the filesystem has not been prepared correctly. However, there is another way to set up the JFFS2 filesystem in FLASH. If you mount a clean (0xff, 0xff,...) FLASH block device as -tjffs2, Linux will create the JFFS2 fs itself.

Procedue (on BOA):

  • fis create ...
  • fis erase ...
  • boot Linux with a root elsewhere (NFS)
  • in Linux: mount -tjffs2 /dev/mtdblock2 /mnt
  • voila, the fs is created; now, you can untar or cp -a root contents to /mnt

--Pecam1 13:22, 16 February 2009 (CET)

Linux kernel commandline to boot using root in FLASH block device is following:

   ex -c "root=/dev/mtdblock2 ro rootfstype=jffs2"

The number 2 of memory tech. device is a number of "jffs2" block in FLASH partitions list, example (0: (reserved), 1: RedBoot, 2: jffs,...):

   RedBoot> fis list
   Name              FLASH addr  Mem addr    Length      Entry point
   (reserved)        0xF0000000  0xF0000000  0x00010000  0x00000000
   RedBoot           0xF0010000  0xF0010000  0x00050000  0x00000000
   jffs2             0xF0060000  0x00100000  0x00FF0000  0x00100000
   Linux             0xF1050000  0x00800000  0x00110000  0x00800000
   FIS directory     0xF1FF0000  0xF1FF0000  0x0000F000  0x00000000
   RedBoot config    0xF1FFF000  0xF1FFF000  0x00001000  0x00000000

Login with telnet

telnet <ip address of boa>

Log in as root, ask me for the password. --Sojka 20:42, 21 March 2007 (CET)

Setting up bootloder (automatic boot)

Use 'fconfig' command (see RedBoot manual) to set up bootloader configuration. Recommended configuration:

Run script at boot: true
Boot script:
 load zImage.elf
 ex -c "root=/dev/nfs rw nfsroot=192.168.123.254:/var/MPC5200_root ip=dhcp"
Boot script timeout (1000ms resolution): 10 
Use BOOTP for network configuration: true
Default server IP address: IP address of your computer
FEC Network hardware address [MAC]: choose MAC address of the unit (example: 0x00:0x00:0x00:0x00:0x00:0x02)
GDB connection port: 9000
Force console for special debug messages: false
Network debug at boot time: false
Update RedBoot non-volatile configuration - continue (y/n)? y

Socketcan

To set up can interface, it is necessary to configure the communication speed first and then bring the interface up. Communication speed can be set up using following command (for can0 interface @ 1Mbit):

echo 660000 >/sys/class/net/can0/can_baudrate

For newer version of socketcan you must use:

echo 660000 >/sys/class/net/can0/can_bittiming/bitrate

The constant 660000 for 1Mbit speed was found experimentally, driver seems to calculate the transmission speed improperly. To bring up the can network interface, use the same command as with any other network interface, i.e.

ifconfig can0 up

The most comfortable way of setting up both can interfaces upon startup of system is to place following script to /etc/init.d/ (name it 'can', for example)

echo 660000 >/sys/class/net/can0/can_baudrate
echo 660000 >/sys/class/net/can1/can_baudrate
ifconfig can0 up
ifconfig can1 up

CanFestival

Obtaining and building CanFestival

CanFestival driver source can be downloaded from. The primary way how to do it is to check out the source directory from CanFestival CVS by these steps:

cvs -d:pserver:anonymous@lolitech.dyndns.org:/canfestival login
(type return, without entering a password)

The system will respond:

Logging in to :pserver:anonymous@lolitech.dyndns.org:2401/canfestival

Then, enter:

cvs -z3 -d:pserver:anonymous@lolitech.dyndns.org:/canfestival co -P CanFestival-3

Then insert CanFestival folder and run this commands:

./configure --timers=unix --can=socket --cc=powerpc-603e-linux-gnu-gcc --arch=ppc --os=linux --target=unix 
make
make install

Building of CanFestival will produce some libraries and copy them to /usr/powerpc-603e-linux-gnu/lib folder.

Setting up local CANopen node

CanFestival source includes tool called objdictedit. This program has graphical user interface and serves to creating configuration of the CANopen node of application we develop. It is started by command objdictedit. Using this program you can create the object dictionary for the CanFestival. Mainly it is necessary to set up all SDO and PDO, the node has to send and receive. To each PDO you have to define more things - PDO receive or transmit, variable to be mapped and variable mapping. The variable will then be used in application code to exchange data between CanFestival driver and application. If you set up PDOs here they will be sent and received automatically and the values will be stored into mapped variable. Setting up SDO means that you can use it in your application, but if you want to send it, it has to be done in code. After creating this basic configuration you have to build the dictionary which results into to files with extensions .h and .c. You have to link these files with your application.

Initializing and starting CanFestival

To explain how to use CanFestival I include some code examples. It supposes node configuration generated by objdictedit which name is canopen. It is then used as prefix of automatically generated functions and variables (canopen_Data is for example object dictionary used by CanFestival). Header canfestival.h has to be included. For start using CanFestival it is necessary to load dynamic library with CAN bus driver API created while compiling CanFestival source. In the example SocketCan driver is used to access CAN bus.

if(!LoadCanDriver("libcanfestival_can_socket.so")) {
	exit -1;
}

Then you have to open CAN device. Parameters of the communication have to be prepared in structure of type s_Board. In this case CAN is set to use device can1 and baudrate 1Mbps. Handler of the bus is then stored to variable of type CAN_HANDLE.

/**
 * CAN board definition.
 * Device name can1, baudrate 1M
 */
s_BOARD canopen_board = {"1", "1000"};
CAN_HANDLE canopen_handle;

if(!(canopen_handle = canOpen(&canopen_board, &canopen_Data))) {
	exit -1;
}

CanFestival implements callbacks to some events like change of state or message reception. There are pointers to callback functions in canopen_Data structure. You can assign your own functions to these pointers or leave them unused.

canopen_Data.initialisation = canopen_initialisation;
canopen_Data.preOperational = canopen_preOperational; 
canopen_Data.operational = canopen_operational; 
canopen_Data.post_sync = canopen_post_sync; 
canopen_Data.post_TPDO = canopen_post_TPDO; 
canopen_Data.stopped = canopen_stopped; 

After setting up these few things you have to call function StartTimerLoop which initializes CanFestival timers. As an argument you have to insert pointer to the first function you want to proceed after starting the timers.

StartTimerLoop(&initNode); 

Here is an example of such a function. It sets local node ID to 1 and bring the node to operation state. Callback functions are called after changing state if used.

void initNode(CO_Data * d, UNS32 id)
{
	setNodeId(&canopen_Data, 0x01);

setState(&canopen_Data, Initialisation); setState(&canopen_Data, Operational);

}

Stopping CanFestival

After finishing work with CANopen it is good to stop the communication and timers and close the device. It is done by these few functions.

setState(&canopen_Data, Stopped);
StopTimerLoop();
canClose(&canopen_Data);
canopen_handle = NULL;

Writing to Object dictionary

CANopen devices and all network services of each node are configured by writing to device object dictionary (OD). It is different while writing to local OD or OD of some network device.

Writing to local OD

Function WriteLocalDict is used for writing to OD of local node managed by CanFestival.

UNS32 writeLocalDict( CO_Data* d, 
UNS16 wIndex, 
UNS8 bSubindex, 
void * pSourceData, 
UNS8 * pExpectedSize, 
UNS8 checkAccess);

Meaning of function arguments:

d - pointer to local object dictionary structure
wIndex - the index in the object dictionary where you want to write an entry
bSubindex - the subindex of the Index. e.g. mostly subindex 0 is used to tell you how many valid entries you can find in this   index. Look at the canopen standard for further information
pbSourceData - pointer to the variable that holds the value that should be copied into the object dictionary
pExpectedSize - pointer to variable with size of the data to be written
CheckAccess - if other than 0, do not read if the data is Read Only or Constant

Writing to network OD

It is necessary to use SDO service for writing data to OD of some network device. Each CANopen device has at least one SDO server. It means that it is able to receive SDOs with one ID and answer by SDOs with another ID. It is usual that the server listen for SDOs with ID 0x600 + ID of the node and transmits SDOs of ID 0x580 + node ID. Each SDO we want to use has to be defined while creating node configuration by objdictedit. Then the SDO is sent by calling appropriate function. The best is to use function writeNetworkDictCallBack which syntax is shown below.

UNS8 writeNetworkDictCallBack (CO_Data* d, 
UNS8 nodeId, 
UNS16 index,
UNS8 subIndex, 
UNS8 count, 
UNS8 dataType, 
void *data, 
SDOCallback_t Callback);

Meaning of function arguments:

d - pointer to local object dictionary structure
nodeId - ID of the device we want to send SDO
index - the index in the object dictionary where you want to write an entry
subIndex - the subindex of the Index. e.g. mostly subindex 0 is used to tell you how many valid entries you can find in this index. Look at the canopen standard for further information
count - number of bytes to be written
dataType - type of the data, use 0 for integers, real numbers and other values
data - pointer to the data
Callback - pointer to a function which is called after finishing the transfer

The SDO service is by definition confirmed. It means that SDO server sends response with result of the transfer after each SDO reception. This response has to be read by client to be sure that the data were written correctly. The result should be read in your function which pointer is given to the function writeNetworkDictCallBack as parameter callback. The result of SDO transfer in such a function is read by CanFestival function getWriteResultNetworkDict. This function has to be called after each SDO transmission because it releases line used to transfer. Header of this function is:

UNS8 getWriteResultNetworkDict (CO_Data* d, UNS8 nodeId, UNS32 * abortCode);

And meaning of function arguments is:

d - pointer to local object dictionary structure
nodeId - ID of the device we have sent SDO
abortCode - pointer to the variable where error code is written in case of error

The function can return one of these values according to the SDO transfer state:

SDO_FINISHED - data is available
SDO_ABORTED_RCV - Transfer failed. (abort SDO received)
SDO_ABORTED_INTERNAL - Transfer failed. Internal abort.
SDO_DOWNLOAD_IN_PROGRESS - Data not yet available

The function can be used in cycle waiting while return value is SDO_DOWNLOAD_IN_PROGRESS. But the better solution is calling it in callback function from writeNetworkDictCallBack. The callback is call after finishing the transfer.

Using PDO service

Using PDO service for data exchange is very easy in CanFestival. The most usual transmission type of PDOs is that they are transmitted after SYNC message. In this case it just has to be set up in objdictedit configuration and then it works, reads and stores values into mapped variables. After each PDO reception or transmission post_TPDO callback is called if used. Sometimes it is necessary to send PDO from code without SYNC message reception. This is done by calling the function sendPDOevent with this syntax:

UNS8 sendPDOevent(CO_Data* d);

where d is the pointer to local object dictionary structure. This function sends all PDOs defined by objdictedit and transmission type after event (0x255).

Generating SYNC message

If you want to set up local node to become the SYNC server you have to write some information to local OD. Here is an example of function which set up the SYNC messages generation:

/**
 * This function initializes local canopen node to send SYNC message
 * with given period. 
 * @param d - local object dictionary
 * @param period - period of the SYNC message in us
 */
void synchro_setup(CO_Data *d, unsigned long period)
{
	UNS32 SYNC_COBID = 0x40000080;
	UNS32 SYNC_INTER = period;
	UNS8 size = sizeof(UNS32); 
	writeLocalDict(d, 0x1006, 0x0, &SYNC_INTER, &size, RW);
	writeLocalDict(d, 0x1005, 0x0, &SYNC_COBID, &size, RW);
}

According to CANopen specification ID of the SYNC message is 0x80. After the setup it can be started by command startSYNC(CO_Data *d) and stopped by command stopSYNC(CO_Data *d).

SDO and PDO example

At the end I attach example of a function (cpd_start()) which starts some device communicating by CANopen. The ID of the device is given by the parameter. The other function (cpd_checkSDO_start()) is callback used to handle SDO transfer result. It is necessary to wait until one SDO transfer is finished before starting some other. Global variable cpd_init_step is used for counting actual step of SDO transfer. If some SDO transfer fails it is set to -1 and the startup process is terminated.

/**
 * This function is given to the writeNetworkDict function as a callback.
 * It checks the result of SDO transmition and after finishing the transmition
 * it closes the transfer.
 * @param d - local object disctionary
 * @param nodeID - ID of the node which the local node is communicating with
 */ 
void cpd_checkSDO_start(CO_Data* d, UNS8 nodeId)
{
	UNS32 abortCode;	
	if(getWriteResultNetworkDict (d, nodeId, &abortCode) != SDO_FINISHED) {
		cpd_init_step = -1;
	}
	closeSDOtransfer(&canopen_Data, nodeId, SDO_CLIENT);
	cpd_start(&canopen_Data, nodeId);
}

/**
 * This function switch canopen device into operational state. 
 * @param d - local object dictionary
 * @param nodeId - ID of the device
 * return 0 - ok, -1 - failed
 */
int cpd_start(CO_Data *d, UNS8 nodeId)
{
	UNS8 data8;
	UNS16 data16;
	UNS32 data32;
	switch(cpd_init_step++) {
		case 0:
			masterSendNMTstateChange(d, nodeId, NMT_Start_Node);
			cpd_controlword = 0;
                       sendPDOevent(d);
			cpd_controlword = 6;
                       sendPDOevent(d);
			cpd_controlword = 0x0F;
                       sendPDOevent(d);

			// Start operational mode
			data8 = 0xFC;
			writeNetworkDictCallBack(d, nodeId, 0x6060, 0x00, 1, 0, &data8, cpd_checkSDO_start);
			break;
		case 1:
			// Check operation status
			readNetworkDictCallback(d, nodeId, 0x6061, 0x00, 0, cpd_checkSDO_start);
			break;
		case 2:
			// Setpoint specification
			data16 = 0x0002;
			writeNetworkDictCallBack(d, nodeId, 0x301B, 0x11, 2, 0, &data16, cpd_checkSDO_start);
			break;
		case 3:
			canopen_init_result = 0;
			cpd_init_step = 0;
			break;
		case -1:
			canopen_init_result = -1;
			cpd_init_step = 0;
			break;
	}
	return 0;
}

Emergency message

New version of CanFestival is extended by EMCY messages support. There is callback added which can be set to point to your own EMCY message handler.This handler has to be a function with three parameters defined in this way:

void my_post_emcy(UNS8 nodeID, UNS16 errCode, UNS8 errReg)

After reception of an EMCY message this callback is called. The parameters keep information about node ID of the EMCY producer, error code and content of the error register. To register your handler you have to set the callback in CanFestival initialization.

my_Data.post_emcy = my_post_emcy;