chakokuのブログ(rev4)

日々のごった煮ブログです

nRF51822(micro:bitのマイコン)でシリアル通信

micro:bitのボードに対してランタイムを使わず素のマイコンにプログラムを書き込んで動かす取り組みを行ってます。前回はLチカができて、次はシリアル通信の実装に取り組んでます。
シリアルはデバッグ機能を提供しているMKL26Z128VFM4というマイコンを介して通信可能で、そもそもこのMKL26Z128VFM4というマイコンはJ-LINKのデバッグ手段として稼働しています(と理解しています)。J-LINKが仮想シリアルを世話してくれているので、micro:bitの本体のマイコンであるnRF51822のシリアルがJ-LINKを介して、USBでPCと接続され、仮想COMポートが実現され、TeraTerm等でシリアル通信ができるというわけでございます。

以下が動作確認したソース。J-LINKの部分はまったく考慮せず、ただ、micro:bitの回路図が示す通り、RxD:P0.25 , TxD:P0.24となるようにGPIOとSerialを設定して、SerialのRx/Txを実装しました。割り込みプログラミングではないので、滅茶苦茶早くキーを叩くと文字化けします。最低限Lチカとシリアルが動いたので、少しづつ肉付けしていけば、そのうち俺インタープリタも乗るはず。。多分。

#include <stdio.h>
//#include <stdlib.h>
//#include <stdint.h>


#define GPIO_BASE 0x50000000
#define GPIO_PIN_CNF_BASE 0x700
#define GPIO_OUTSET 0x508
#define GPIO_OUTCLR 0x50C

#define GPIO_PIN_3   3
#define GPIO_PIN_4   4
#define GPIO_PIN_13  13
#define GPIO_PIN_24  24
#define GPIO_PIN_25  25

#define GPIO_PORT_H 1
#define GPIO_PORT_L 0

#define GPIO_SETUP_OUTPUT 1
#define GPIO_SETUP_INPUT  0

#define UART0_BASE 0x40002000
#define UART0_BAUDRATE 0x524
#define BAUD38400 0x009D5000

#define UART0_STARTRX 0x000  // Start UART receiver
#define UART0_STARTTX 0x008  // Start UART transmitter
#define UART0_PSELTXD 0x50C  // Pin select for TXD
#define UART0_PSELRXD 0x514  // Pin select for RXD
#define UART0_RXDRDY  0x108  // Data received in RXD
#define UART0_TXDRDY  0x11C  // Data sent from TXD
#define UART0_ENABLE  0x500  // Enable UART

#define UART0_RXD 0x518 // RXD register
#define UART0_TXD 0x51C // TXD register

#define UART_WAIT    0
#define UART_NO_WAIT 1

#define TX_PIN GPIO_PIN_24
#define RX_PIN GPIO_PIN_25

void uart_setup(void);
void uart_send(char);
void led_blink(void);
int wait(int);
void led_setup(void);
void gpio_set(int, int);
void gpio_setup(int, int);
char uart_recv(int);



/*********************************************************************
*
*       main()
*
*  Function description
*   Application entry point.
*/
void main(void) {

  char ch;

  led_setup();
  uart_setup();

  printf("Hello World!\n");

  uart_send('>');

  while (1){
    ch = uart_recv(UART_NO_WAIT);
    if(ch == 0){
      ;
    }else if((ch == '\n')||(ch == '\r')){
      uart_send('\r'); 
      uart_send('\n');
      uart_send('>');
    }else{
      led_blink();
      uart_send(ch);
    }
  } 
}

void led_setup(void){

   gpio_setup(GPIO_PIN_4,GPIO_SETUP_OUTPUT);
   gpio_setup(GPIO_PIN_13,GPIO_SETUP_OUTPUT);

   gpio_set(GPIO_PIN_4,GPIO_PORT_L);// pin_4 to L
   gpio_set(GPIO_PIN_13,GPIO_PORT_H);// pin_13 to H

}

void led_blink(void){
  static int state = 0;

  if(state == 0){
    gpio_set(GPIO_PIN_13,GPIO_PORT_H);
    state = 1;
  }else{
    gpio_set(GPIO_PIN_13,GPIO_PORT_L);
    state = 0;
  }
}


void uart_send(char ch){

   unsigned int * addr;

   addr = (unsigned int *)(UART0_BASE + UART0_TXD);
   *addr = (unsigned char)ch;

   addr = (unsigned int *)(UART0_BASE + UART0_TXDRDY);
   while(*addr != 1){
     ;
   }
   *addr = 0;  // clear TXD Ready 
}

char uart_recv(int wait_mode){

   unsigned int * addr;
   char ch;

   addr = (unsigned int *)(UART0_BASE + UART0_RXDRDY);
   if((*addr == 0) && (wait_mode == UART_NO_WAIT)){
     return 0;
   }
   while(*addr != 1){
     ;
   }
   *addr = 0;
   addr = (unsigned int *)(UART0_BASE + UART0_RXD);
   ch = *addr;
   return ch;
}


void uart_setup(void){

  unsigned int * addr;
   unsigned int flg;

   // set TX_PIN as output
   gpio_setup(TX_PIN,GPIO_SETUP_OUTPUT);

   // set RX_PIN as input
   gpio_setup(RX_PIN,GPIO_SETUP_INPUT);

  // set PinNo for TXD
  addr = (unsigned int *)(UART0_BASE + UART0_PSELTXD);
  *addr = TX_PIN;       // p0.24 for TXD

  // set PinNo for RXD
  addr = (unsigned int *)(UART0_BASE + UART0_PSELRXD);         
  *addr = RX_PIN;         // p0.25 for RXD

  // set baudrate
  addr = (unsigned int *)(UART0_BASE +  UART0_BAUDRATE);
  *addr = BAUD38400;   // Baud38400 0x009D5000

  // UART0 enable
  addr = (unsigned int *)(UART0_BASE +  UART0_ENABLE);
  *addr = 4;

  // START TX
  addr = (unsigned int *)(UART0_BASE +  UART0_STARTTX);
  *addr = 1;

  // START RX
  addr = (unsigned int *)(UART0_BASE +  UART0_STARTRX);
  *addr = 1;

  // Clear RXDRDY
  addr = (unsigned int *)(UART0_BASE +  UART0_RXDRDY);
  *addr = 0;

}

//******************************************************

void gpio_setup(int port_no,int dir){

   unsigned int * addr;

   addr = (unsigned int *)(GPIO_BASE + GPIO_PIN_CNF_BASE + port_no * 4);
   if(dir == GPIO_SETUP_OUTPUT){
     *addr = 0x1;   // dir:output
   }else{
     *addr = 0x0;   // dir:input
   }
}

void gpio_set(int port_no,int level){

   unsigned int * addr;

   if(level == GPIO_PORT_H){
     addr = (unsigned int *)(GPIO_BASE + GPIO_OUTSET);
   }else{
     addr = (unsigned int *)(GPIO_BASE + GPIO_OUTCLR);
   }
   *addr = (1 << port_no);
}


//***************************************

int wait(int rate){
  int i,j;
  for(i=0;i<rate;i++){
      for(j=0;j<0xFF;j++){
      ; // nop
    }    
  }
}