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
で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); } }