그동안 mbed를 잘 안 쓰는 데에는 그만한 이유가 있었다. Cortex-M 계열의 여러 MCU들의 통일된 인터페이스라니 이 얼마나 멋진 발상인가. 하지만 여기에도 적서嫡庶의 차별은 엄연히 존재하였으니, 레퍼런스 보드이자 오리지널 보드라 할 수 있는 mbed LPC1768은 사용하는 데에 아무런 제약이 없지만 제휴사의 보드들은 지원하지 않는 API들도 꽤 많았고, 특별한 이유 없이 작동이 되지 않는 경우도 허다했다. 그래서 문제에 집중하기 보다는 기능별로 호환이 되는지, 지원이 제대로 되는지에 관심을 더 쏟게 되면서, 누구 좋으라고 이런 정성을 들여야 하나 하는 회의가 들어 자연스럽게 mbed와는 멀어지게 되었다.
한동안 그렇게 던져두고 있던 mbed를 요즘 다시 들여다볼 일이 생겼는데, 안 본 사이에 많이 변했구나. 요즘도 LPC1768을 제일 먼저 밀어주는지는 모르겠지만, 그리고 여전히 다른 보드들의 호환성이 완전히 지원되지는 않지만, 예전보다는 확실히 달라진 모습을 보여주고 있다. 초기에는 Freescale의 FRDM-KL25Z가 굴욕적인 차별을 홀로 견뎌내었지만 요즘은 호환 보드들이 더 많아진 상황이라 외롭지 않다고 해야 할까. 아무튼 이젠 정말 mbed의 생태계가 갖춰지는 느낌. 솔직히 말해 mbed LPC1768은 약간 시대에 뒤쳐지는 맛이 있다. 특히 보드 설계가 좀 잘못된 감이 없지 않은데, 이 얘기는 다음에 따로 하기로 하고…
그런데 호환 보드들도 갑자기 너무 많아지니까 뭘 골라 먹어야 할지 좀 난감해진다. 특히 STM32 NUCLEO 아이들은 무슨 떼강도 마냥 한꺼번에 덤비니 이거야 원… 하긴 저렇게 많아도 눈길이 가는 건 얼마 없다. STM32F103RB야 워낙 유명한 히트작이니 말할 필요도 없고, L152나 F411 정도는 관심이 가지만 다른 아이들은 참가하는 데에 의의를 두는 게 아닐까 싶은데, 모르지 뭐. 그쪽으로 관심 주는 사람들도 분명 있겠지.
EFM32 Gecko 패밀리가 드디어 mbed 진영에 붙었다는 사실은 정말로 반가운 소식. 드디어 mbed도 저전력 API를 지원한다는 얘기 아닌가. 그리고 도마뱀붙이 아이들도 대세를 따름으로써 주류 시장에 한 발 걸치는 계기를 마련하는 셈이고. 그런데 이로 인해 다른 호환 보드들도 저전력 API를 사용할 수 있다는 얘긴지는 아직 확실하지 않은데, 이 부분은 좀 더 지켜볼 필요가 있을 것 같다.
아무려나 오늘 가지고 놀 아이는 Freescale의 FRDM-K64F, Kinetis MCU 중에서는 제일 덩치 큰 놈이다. Flash와 SRAM도 넉넉하고, Ethernet 인터페이스를 가지고 있고, 기특하게도 Micro SD 카드 인터페이스를 내장하고 있다. TM4C1294 런치패드를 보면서 이게 없어서 얼마나 황당했던가 말이다. 그런 면에서 FRDM-K64F는 적당히 갖출 건 갖추고 있는 아이라 할 수 있다.
Ethernet 인터페이스가 있으니, 그리고 외부 저장장치를 지원하니 당연히 웹서버 같은 걸 만들어 봐야 하지 않겠는가. TCP Socket Server 클래스를 가지고 웹서버를 만들어 봤는데 생각보다 잘 된다. SDHC 카드에 담긴 html 파일을 열어서 클라이언트에 던져주는 기본적인 기능 구현에는 전혀 문제가 없다. pdf 파일이나 이미지 파일도 잘 된다. 다만 파일 입출력의 성능은 어쩔 수 없는 문제. 현재 mbed가 제공하는 SD FileSystem으로는 큰 이미지 파일을 보여주기에는 확실히 버겁다. 작은 규모의 서비스라면 차라리 Flash 메모리 안에 html 파일을 전부 다 때려넣는 방법도 생각해 봐야겠다.
#include "SDFileSystem.h"
#include "EthernetInterface.h"
bool serverIsListened = false;
TCPSocketConnection client;
bool clientIsConnected = false;
DigitalOut led1(LED1); //server listning status
DigitalOut led2(LED2); //socket connecting status
DigitalOut SIGNAL_LED(D13);
SDFileSystem sd(PTE3, PTE1, PTE2, PTE4, "sd"); // MOSI, MISO, SCK, CS
/* returns 1 if str ends with suffix */
int str_ends_with(const char *str, const char *suffix)
if ( str == NULL || suffix == NULL )
size_t str_len = strlen(str);
size_t suffix_len = strlen(suffix);
if (suffix_len > str_len)
return (strncmp(str + str_len - suffix_len, suffix, suffix_len) == 0);
//setup ethernet interface
printf("IP Address is %s\r\n", eth.getIPAddress());
if (strlen(eth.getIPAddress()) == 0)
if (svr.bind(PORT) < 0) {
printf("tcp server bind failed.\r\n");
printf("tcp server bind successed.\r\n");
printf("tcp server listen failed.\r\n");
printf("tcp server is listening...\r\n");
char* get_url(char* buffer)
size_t len = strlen(buffer);
for (int i = 0; i < len; i++) {
if ((buffer[i] == ' ') || (buffer[i] == '\t')) {
void make_response(char* buffer)
//setup http response header & data
char echoHeader[256] = {};
char filename[1024] = {};
char* url = get_url(buffer);
if ((strcmp(url, "/ON") == 0) ||
(strcmp(url, "/on") == 0)) {
url = (char*)"/led-on.html";
if ((strcmp(url, "/OFF") == 0) ||
(strcmp(url, "/off") == 0)) {
url = (char*)"/led-off.html";
sprintf(filename, "/sd/www%s", url);
printf("URL = [%s]\r\n", url);
printf("FILE NAME = [%s]\r\n", filename);
if (strcmp(filename, "/sd/www/") == 0)
sprintf(filename, "/sd/www/index.html");
printf("FINAL FILE NAME = [%s]\r\n", filename);
fp = fopen(filename, "r");
sprintf(echoHeader, "HTTP/1.1 404 Not Found\r\n"
"Content-Type: text/html\r\n"
"Connection: Close\r\n\r\n");
client.send(echoHeader, strlen(echoHeader));
client.send((char*)"FILE NOT FOUND\r\n", 16);
clientIsConnected = false;
printf("echo back done.\r\n");
printf("file size = %d\r\n", sz);
sprintf(echoHeader, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\n", sz);
client.send(echoHeader, strlen(echoHeader));
if (str_ends_with(url, ".html") || str_ends_with(url, ".htm")) {
sprintf(echoHeader, "Content-Type: text/html\r\n");
else if (str_ends_with(url, ".css")) {
sprintf(echoHeader, "Content-Type: text/css\r\n");
else if (str_ends_with(url, ".png")) {
sprintf(echoHeader, "Content-Type: image/png\r\n");
else if (str_ends_with(url, ".jpg")) {
sprintf(echoHeader, "Content-Type: image/jpeg\r\n");
else if (str_ends_with(url, ".gif")) {
sprintf(echoHeader, "Content-Type: image/gif\r\n");
else if (str_ends_with(url, ".3gp")) {
sprintf(echoHeader, "Content-Type: video/mpeg\r\n");
else if (str_ends_with(url, ".pdf")) {
sprintf(echoHeader, "Content-Type: application/pdf\r\n");
else if (str_ends_with(url, ".js")) {
sprintf(echoHeader, "Content-Type: application/x-javascript\r\n");
else if (str_ends_with(url, ".xml")) {
sprintf(echoHeader, "Content-Type: application/xml\r\n");
sprintf(echoHeader, "Content-Type: text\r\n");
client.send(echoHeader, strlen(echoHeader));
sprintf(echoHeader, "Connection: Close\r\n\r\n");
client.send(echoHeader, strlen(echoHeader));
n = fread(resbuffer, sizeof(char), 1023, fp);
client.send(resbuffer, n);
clientIsConnected = false;
printf("echo back done.\r\n");
led_tick.attach(&led_tick_func, 0.5);
printf("HTTP Server initization failed...\r\n");
//listening for http GET request
while (serverIsListened) {
//blocking mode(never timeout)
if (svr.accept(client) < 0) {
printf("failed to accept connection.\r\n");
printf("connection success!\r\nIP: %s\r\n", client.get_address());
clientIsConnected = true;
while (clientIsConnected) {
switch (client.receive(buffer, 1023)) {
printf("recieved buffer is empty.\r\n");
clientIsConnected = false;
printf("failed to read data from client.\r\n");
clientIsConnected = false;
printf("Recieved Data: %d\r\n\r\n%.*s\r\n",
strlen(buffer), strlen(buffer), buffer);
if (buffer[0] == 'G' && buffer[1] == 'E' && buffer[2] == 'T') {
printf("GET request incomming.\r\n");
make_response(buffer + 4);
printf("close connection.\r\ntcp server is listening...\r\n");
Colored by Color Scripter
다음엔 여기에 간단한 CGI 기능을 추가해 볼까. php 같이 만들어 놓은 건 어디 없나…