LPC1768でのMDK-ARMデバッグ

1)LPC1768のファームウエアをアップデートする。
  最新のファームウエアはCMSIS-DAPに対応しているらしい。
  今回入れたのは141212

2)正しくファームウエアがアップデートされたかは、mbedのドライブ内にあるMBED.HTMに書かれている。
  このMBED.HTMをテキストファイルで開き、firmware=と書かれたところにバージョンが記されている。
  今回だと、firmware=141212

3)ホスト(Windows)のUSBドライバを更新する。
  http://developer.mbed.org/handbook/Windows-serial-configuration#1-download-the-mbed-windows-serial-port
  を開き、「Download latest driver」の部分からドライバをダウンロード、インストールする。

4)メニューの [Flash] -> [Configure Flash Tools...] を選択しUtilitiesタブを選択。
  use Target Driver for Flash ProgrammingでCMSS-DAP Debuggerを選択する。

5)同Debugタブで 右側のUseでもCMSS-DAP Debuggerを選択する。
  Settingsを押すとアダプタとしてMBED CMSIS-DAPが選択されていることを確認する。

    • -

PCを更新したので、久しぶりにμVision5.23.0.0をインストールしてLPC1768をオフラインデバッグしようとしたが
以下のようなエラーが出てロードに失敗する。

PDSC: Cannot recover from reset
Error: Flash Download failed - Target DLL has been cancelled

色々ネットで調べたがわからず(同じように困っている人はいた)。
設定をいろいろ変えていたら以下の対処で上手く動いた。

Option for Target... のDebugタブを表示させる。
Use CMSIS-Debugger の右側 Settings ボタンを押す。
Cortex-M Target Driver SetupのDebugタブを表示させる。
下部のDebug枠のReset:をSYSRESETREQからHW RESETに変更する。

mmapでのGPIO設定

mmapによるユーザランドからのGPIO制御。
デバイスドライバによる方法よりオーバヘッドが少ない。

/* gpioMmap.h */


// definition
typedef enum{
  E_GPFSEL_INPUT = 0,
  E_GPFSEL_OUTPUT = 1,
  E_GPFSEL_F0 = 4,
  E_GPFSEL_F1 = 5,
  E_GPFSEL_F2 = 6,
  E_GPFSEL_F3 = 7,
  E_GPFSEL_F4 = 3,
  E_GPFSEL_F5 = 2
} E_GPFSEL;


// finction prototypes
void gpio_open(void);
void gpio_close(void);
void set_gpio_function(int pin, E_GPFSEL function);
void set_gpio(int pin, int level);
int get_gpio(int pin);
// gpioMmap.c

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>

#include "gpioMmap.h"

//----------
// Macros
#define   PRINTLINE printf("%s:%d\n", __FUNCTION__, __LINE__)

#define PAGE_SIZE (4*1024)
#define BLOCK_SIZE (4*1024)
#define GPIO_BASE 0x20200000

//----------
// global variables
int mem_fd;           // mmap file
void *ptr;            // virtual memory allocated by alloc

// the variable gpio points to 0x20200000, that is GPIO registers
// starts from GPFSEL0 to GPPUDCLK1
volatile unsigned long *gpio;    // 0x20200000
volatile unsigned long *gpfsel;  // 0x20200000
volatile unsigned long *gpset;   // 0x2020001C
volatile unsigned long *gpclr;   // 0x20200028
volatile unsigned long *gplev;   // 0x20200034


/*-----------------------------------------------
 * Open the GPIO Lib
 */
void gpio_open(void)
{
  char *gpio_map;
  char *gpio_mem;

  PRINTLINE;

  // open /dev/mem
  mem_fd = open("/dev/mem", O_RDWR | O_SYNC);
  if(mem_fd < 0){
    perror("Fail to open /dev/mem");
    exit(-1);
  }

  ptr = malloc(BLOCK_SIZE + (PAGE_SIZE - 1));
  if(ptr == NULL){
    perror("Fail to malloc");
    exit(-1);
  }

  // align page boundary
  if((unsigned long)ptr % PAGE_SIZE != 0){
    gpio_mem = ptr + (PAGE_SIZE - ((unsigned long)ptr % PAGE_SIZE));
  }
  else{
    gpio_mem = ptr;
  }

  // map virtual to physical
  gpio_map = (char *)mmap(
			  (caddr_t)gpio_mem,
			  BLOCK_SIZE,
			  PROT_READ | PROT_WRITE,
			  MAP_SHARED | MAP_FIXED,
	       		  mem_fd,
      			  GPIO_BASE
			  );
  if((long)gpio_map < 0){
    perror("Fail to mmap");
    exit(-1);
  }

  gpio = (volatile unsigned long *)gpio_map;

  gpfsel = gpio + (0x00/4);
  gpset  = gpio + (0x1C/4);
  gpclr  = gpio + (0x28/4);
  gplev  = gpio + (0x34/4);

}



/*-----------------------------------------------
 * Close the GPIO Lib
 */
void gpio_close(void)
{
  close(mem_fd);
  free(ptr);
}


/*-----------------------------------------------
 * set function to the GPIO pin
 * once clear the 3 bits then set the function to the 3 bits
 */
void set_gpio_function(int pin, E_GPFSEL function)
{
  volatile unsigned long *ptr;

  ptr = (gpfsel + (pin / 10));
  *ptr &= ~(7 << ((pin % 10) * 3));
  *ptr |= (function << ((pin % 10) * 3));
}


/*-----------------------------------------------
 * set the GPIO pin to High/Low
 */
void set_gpio(int pin, int level)
{
  volatile unsigned long *ptr;

  if(level == 1) ptr = gpset;
  else           ptr = gpclr;

  if(pin < 32){ ptr = ptr + 0; }
  else{         ptr = ptr + 1;  pin -= 32; }
  *ptr = 1 << pin;
}


/*-----------------------------------------------
 * get the level of the GPIO pin
 */
int get_gpio(int pin)
{
  volatile unsigned long *gp;

  if(pin < 32){ gp = gplev + 0; }
  else{         gp = gplev + 1;  pin -= 32; }

  return (((*gp) >> pin) & 1);
}

無線LAN設定

無線LANのIPアドレス設定
/etc/network/interfaces
を以下のように編集。

(1)DHCPの場合

allow-hotplug wlan0
iface wlan0 inet dhcp
wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf
iface default inet dhcp

(2)IPアドレス固定の場合

allow-hotplug wlan0
iface wlan0 inet static
address 192.168.1.2 ← 割り当てたい固定IPアドレス値
netmask 255.255.255.0
gateway 192.168.1.1 ← ゲートウエーIP
dns-nameservers 192.168.1.1 ← DNSサーバIP
wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf
iface default inet dhcp

さらに以下のファイルを
/etc/wpa_suoplicant/wpa_supplicant.conf

$ wpa_passphrase >> wpa_supplicant.conf
でkey値とSSIDを書き込み(ハッシュを生成するため)、それ以外の項目を以下のように追記。

ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1

network={
	ssid="<SSID>"
	key_mgmt=WPA-PSK
	proto=WPA2
	pairwise=TKIP CCMP
	group=TKIP CCMP
	#psk="<KEY>"
	psk=<KEY>のハッシュ値
}

設定を反映させるには
$ ipdown wlan0
$ifup wlan0
面倒ならばリブートする。


ただ、何故か無線経由では接続できるまでに時間がかかる。
そのうち、つながるようになっている。

シリアルコンソール画面サイズ変更

シリアルコンソールでログインした場合の画面サイズの変更方法
※SSHでログインする場合はホスト側のコンソールのウインドウサイズ変更に合わせて変更できるが
 シリアルコンソールの場合は80×24のままとなる。

.profileに以下を記述
stty rows 45 columns 150

ログインし直すと画面サイズを上記指定したサイズに変わっている。

またはシェル上で

$ stty rows 45
$ stty cols 150

とする。すると動的にシリアルコンソールの画面のサイズを変更できる。
(こちらは一時的な設定)

DCモータ制御

GPIOライブラリヘッダファイル

/* gpio_control.h */

#ifndef __GPIO_CONTROL_H__
#define __GPIO_CONTROL_H__

typedef enum {
  E_GPIO_OUT,
  E_GPIO_IN
} E_GPIO_DIRECTION;

typedef enum {
  E_GPIO_1,
  E_GPIO_0
} E_GPIO_VALUE;

typedef enum {
  E_GPIO_OK,
  E_GPIO_NG
} E_GPIO_RESULT;


E_GPIO_RESULT initGPIO(int num, E_GPIO_DIRECTION dir);
E_GPIO_RESULT writeGPIO(int num, E_GPIO_VALUE value);
E_GPIO_VALUE readGPIO(int num);


#endif


GPIOライブラリソースファイル

/* gpio_control.c */

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <time.h>
#include <sys/time.h>

#include "gpio_control.h"

#define PRINTLINE   printf("%s, %d\n", __FUNCTION__, __LINE__);

//------------------------------
E_GPIO_RESULT initGPIO(int num, E_GPIO_DIRECTION dir)
{
  char buff[32];
  char path[64];
  E_GPIO_RESULT ret;

  printf("%s : %d : %d\n", __FUNCTION__, num, dir);

  sprintf(buff, "%d", num);
  ret = writeValue("/sys/class/gpio/export", buff);


  if(dir == E_GPIO_OUT){
    sprintf(buff, "out");
  }
  else{
    sprintf(buff, "in");
  }
  sprintf(path, "/sys/class/gpio/gpio%d/direction",  num);
  ret = writeValue(path, buff);

 return ret;
}

//------------------------------
E_GPIO_RESULT writeGPIO(int num, E_GPIO_VALUE value)
{
  char buff[32];
  char path[64];
  E_GPIO_RESULT ret;

  printf("%s : %d : %d\n", __FUNCTION__, num, value);

  if(value == E_GPIO_1){
    sprintf(buff, "1");
  }
  else{
    sprintf(buff, "0");
  }
  sprintf(path, "/sys/class/gpio/gpio%d/value", num);

  ret = writeValue(path, buff);

  return ret;
}

//------------------------------
E_GPIO_VALUE readGPIO(int num)
{
  char buff[32];
  char path[64];
  E_GPIO_VALUE ret;
  int n;

  printf("%s : %d\n", __FUNCTION__, num);

  sprintf(path, "/sys/class/gpio/gpio%d/value", num);

  ret = readValue(path, buff, 32);
  n = atoi(buff);
  if(n == 1){
    ret = E_GPIO_1;
  }
  else{
    ret = E_GPIO_0;
  }

  return ret;
}


//------------------------------
int writeValue(char *file, char *value)
{
  int fd;
  int ret;

  printf("%s : %s : %s\n", __FUNCTION__, file, value);

  fd = open(file, O_WRONLY);
  if(fd < 0){
    PRINTLINE
    perror("GPIO open error");
    return -1;
  }

  ret = write(fd, value, strlen(value));
  if(ret < 0){
    PRINTLINE
    perror("GPIO write error");
    return -1;
  }

  ret = close(fd);
  if(ret < 0){
    PRINTLINE
    perror("GPIO close error");
    return -1;
  }
  return 0;
}

//------------------------------
int readValue(char *file, char *buff, int length)
{
  int fd;
  int ret;

  printf("%s : %s\n", __FUNCTION__, file);

  fd = open(file, O_RDONLY);
  if(fd < 0){
    PRINTLINE
    perror("GPIO open error");
    return -1;
  }

  ret = read(fd, buff, length);
  if(ret < 0){
    PRINTLINE
    perror("GPIO read error");
    return -1;
  }

  ret = close(fd);
  if(ret < 0){
    PRINTLINE
    perror("GPIO close error");
    return -1;
  }

  printf("%s : %s\n",file, buff);
  return 0;
}

メインプログラム
モータドライバのIN1、IN2をGPIOの25、24に接続している。
キーボード上n,r,b,sで制御できるようにしている。

// exp_moterdrive.c

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <time.h>
#include <sys/time.h>

#include "gpio_control.h"


int md_init(void);
int md_normal(void);
int md_reverse(void);
int md_stop(void);
int md_brake(void);


#define PRINTLINE   printf("%s, %d\n", __FUNCTION__, __LINE__);

//------------------------------
int main(void)
{
  char c;

PRINTLINE
  md_init();
  md_stop();

  printf("----------\n");
  printf(" Enter n/r/b/s\n");
  printf("----------\n");


  while(1){
    c = getchar();
    switch(c){
    case 'n':
      md_normal();
      break;
    case 's':
      md_stop();
      break;
    case 'r':
      md_reverse();
      break;
    case 'b':
      md_brake();
      break;
    default:
      printf("----------\n");
      printf(" n : normal\n");
      printf(" r : reverse\n");
      printf(" b : brake\n");
      printf(" s : stop\n");
      printf("----------\n");
      break;
    }
  }

}

//------------------------------
int md_init(void)
{
  E_GPIO_RESULT ret;

PRINTLINE
  ret = initGPIO(24, E_GPIO_OUT);
  ret = initGPIO(25, E_GPIO_OUT);
}

int md_normal(void)
{
  E_GPIO_RESULT ret;

PRINTLINE
  ret = writeGPIO(24, E_GPIO_0);
  ret = writeGPIO(25, E_GPIO_1);
}

int md_reverse(void)
{
  E_GPIO_RESULT ret;

PRINTLINE
  ret = writeGPIO(24, E_GPIO_1);
  ret = writeGPIO(25, E_GPIO_0);
}

int md_stop(void)
{
  E_GPIO_RESULT ret;

PRINTLINE
  ret = writeGPIO(24, E_GPIO_0);
  ret = writeGPIO(25, E_GPIO_0);
}

int md_brake(void)
{
  E_GPIO_RESULT ret;

PRINTLINE
  ret = writeGPIO(24, E_GPIO_1);
  ret = writeGPIO(25, E_GPIO_1);
}

照度センサー2

前回の照度センサーの読み込みを自動起動で定周期で継続させる。
/etc/rc.localでプログラムを起動しようとしたが、うまくいかない(なぜかよくわかっていない)。
代替としてcronで定周期起動を行うこととする。

rootになって、
$ crontab -e
でcronのエディタを起動し、以下を追記

/1 * * * * /home/pi/exp_photo_register/photo_register_once

書き込んで、終了させる。
上記は1分ごとにphoto_register_onceというプログラムが実行される。
photo_register_onceは前回の照度船さとは違い、cronから定期的に起動されるため、
内部にwhileループを持たない。
照度データの保存場所はマウントしたHDDにしている。

// spi_photo_register.c

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <time.h>
#include <sys/time.h>

#define CS 0
#define CLOCK_SPEED 2000000

#define SAMPLING_INTERVAL 60

#define PRINTLINE   printf("%s, %d\n", __FUNCTION__, __LINE__);

int spi_read_write(void);

//------------------------------
int main(void)
{
  spi_read_write();
}

//------------------------------
int spi_read_write(void)
{
  int pf;
  int ret;
  unsigned char data[2];
  unsigned short sdata[2];
  unsigned short value;

  float vf;

  struct timespec ts;
  ts.tv_sec = SAMPLING_INTERVAL;
  ts.tv_nsec = 0;

  time_t t;
  char *t_str;

  FILE *fd;
  char str[256];

PRINTLINE

  pf = wiringPiSPISetup(CS, CLOCK_SPEED);
  if(pf < 0){
    perror("Fail to wiringPiSPISetup");
    exit(1);
  }

  while(1){

    // Write and Read DAC(MCP3002) via SPI
    //
    // For MCP3002
    //
    // [send data]
    // - mode = single ended
    // - channel selection = 0
    // - bit order = MSBF (MSB first)
    // 
    // +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+
    // | x| 1|  |  |  | x| x| x| | x| x| x| x| x| x| x| x| 
    // +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+
    //         |  |  |
    //         |  |  +------ MSBF
    //         |  +--------- ODD/SIGN
    //         +------------ SGL/DIFF
    // 
    // [received data]
    // +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+
    // | x| x| x| x| x| 0|B9|B8| |B7|B7|B5|B4|B3|B2|B1|B0| 
    // +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+
    // 
    data[0] = 0b01101000;
    data[1] = 0b00000000;
    ret = wiringPiSPIDataRW(CS, data, 2);
    if(ret < 0){
      perror("Fail to wiringPiSPIDataRW");
      exit(1);
    }

    sdata[0] = (unsigned short)data[0];
    sdata[1] = (unsigned short)data[1];
    value = ((sdata[0] << 8) | sdata[1]) & 0x03FF;

    // transform degital value to voltage
    vf = value;
    vf = vf*3.3/1024;

#if 1 // date and time
    t = time(NULL);
    t_str = ctime(&t);
    t_str[strlen(t_str)-1] = '\0';
    sprintf(str, "%s => %1.6f\n", t_str, vf);
#endif

#if 1 // to store the record to a file.
    fd = fopen("/mnt/hdd1/photo_record.txt", "a");
    if(fd < 0){
      perror("Fail to open file");
      exit(1);
    }
    fprintf(fd, str);
    fclose(fd);
#endif

    nanosleep(&ts,NULL);
  }


}