PICとRPI4Bのuartシリアル通信  0. Hello

ラズパイ５は、AIハット、AIカメラも発売され、大変話題です。さらにPCIe搭載のCompute Module 5も発売されて、アカデミックで設立されたラズベリーですが、ついに株式上場もしました。ただし今回は、今では少しレトロになってしまったRPI4Bを使います。このRPI4BとMicrochip社のマイコンPIC18Fとの、2.304MbpsでのUART高速通信を試行しました。

![0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3970076/5ec1dfbf-da61-062d-fc65-863d4998a729.png)

配線図です。今回使うPIC18F2620は、5Vです。一方、RPI4Bのロジックレベルは、3.3Vです。レベル変換には、秋月電子通商のFXMA108モジュールを使いました。（OEピンを100KΩで5Vのhighにプルアップして、disable状態です。PIC5VとRPI3.3Vの2状態とFXMA108の1状態です。2+1 = 3 statesです。PIC起動時にプログラム上からlowにして、FXMA108をenableにしています。）そしてブレッドボードでは失敗したので、ユニバーサル基板にハンダ付しました。さらに0.2sqの単線（撚り線ではなく）を使用しました。実行結果は、2.304Mbpsでは延長５０ｃｍでした。１ｍまで延長すると、460Kbpsまで落ちました。明らかに、通信速度は、導線の長さでした。 
言い忘れましたが、今回、RPIとPICのuart通信用に、joint-boardを作成して使用しました（下図）。RPI3.3V側へ、直に接続すると、高速通信が可能でした。（PICへ、50ｃｍ）
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3970076/555df744-e7d8-b4b5-f7eb-d6edc9819769.png)

次は、今回使用したラズパイ側のPythonプログラムです。BookwormのPython 3.11.2をThonny上で動作させています。またRPI4BのUARTは、Serial Consoleをオフ、Serialをオンにしただけの簡易設定です。mini UART です。
先にPICを起動し、受信待機状態にします。
RPI4BのThonnyから、"Hello PIC Im Pi.Hello PIC Im Pi." をPICへ送信します。
Thonnyで、"HELLO Pi Im PIC@" をPICから受信すれば、2.304MbpsでのUART送受信が成功です。
同じRPI4Bで、Buster(x32)とBookworm(x64)を試してみましたが、どちらも以下のプログラムで動きます。Buster(x32)の方が、V2カメラ・画像解析のソフトが充実・完成しているので、現実的には使い易いですが。

```python
#RPI-0-uart-tx.py
#Serial Console OFF, Serial ON
#RPI4B Buster(x32) Python 3.7.3 (x32) Thonny, and RUN  or 
#RPI4B bookworm(x64) Python 3.11.2 Thonny, and RUN

import serial

#Open SERIALttyS0
SERIALttyS0 = serial.Serial('/dev/ttyS0', 2304000, timeout=1)

#Set SendMessage
SendMessage = "Hello PIC Im Pi.Hello PIC Im Pi."
#Send Command
SERIALttyS0.write(SendMessage.encode())

#Receive ReturnMessage and print
binary_ReturnMessage = SERIALttyS0.readline()
ReturnMessage = binary_ReturnMessage.decode()
print(ReturnMessage)

#Close SERIALttyS0
SERIALttyS0.close()
```
次はPIC側、つまりPIC18F2620のXC8プログラムです。Microchip社のMPLAB XIDEとXC8を使います。開発環境は、x64ビットWindowsパソコン用のMPLAB X IDE v6.00とXC8 Compiler v2.4.0です。PICkit3が使える最終版です。また26K22でも、プログラム中でコメントアウトしているconfigとアナログ設定を入れ替えるだけで、動きます。PIC18F2620と26K22の相違点は多いですが、今回のUARTに関しては同じです。

```
//main.c    MPLAB  X IDE v6.00,  XC8 Compiler v2.4.0, (C90),  PICkit3
#include <xc.h>

#define _XTAL_FREQ 36864000

#define LED_A0			LATA0
#define FXMA_CS0_TRIS	TRISC0
#define FXMA_CS0_IO		LATC0

//2620
#pragma config OSC = HSPLL
#pragma config FCMEN = OFF
#pragma config IESO = OFF
#pragma config PWRT = ON
#pragma config BOREN = OFF
#pragma config BORV = 3
#pragma config WDT = OFF
#pragma config WDTPS = 32768
#pragma config CCP2MX = PORTBE
#pragma config PBADEN = OFF
#pragma config LPT1OSC = OFF
#pragma config MCLRE = ON
#pragma config STVREN = OFF
#pragma config LVP = OFF
#pragma config XINST = OFF
#pragma config CP0 = OFF
#pragma config CP1 = OFF
#pragma config CP2 = OFF
#pragma config CP3 = OFF
#pragma config CPB = OFF
#pragma config CPD = OFF
#pragma config WRT0 = OFF
#pragma config WRT1 = OFF
#pragma config WRT2 = OFF
#pragma config WRT3 = OFF
#pragma config WRTC = OFF
#pragma config WRTB = OFF
#pragma config WRTD = OFF
#pragma config EBTR0 = OFF
#pragma config EBTR1 = OFF
#pragma config EBTR2 = OFF
#pragma config EBTR3 = OFF
#pragma config EBTRB = OFF
////26k22
//#pragma config FOSC = HSHP
//#pragma config PLLCFG = ON
//#pragma config PRICLKEN = ON
//#pragma config FCMEN = OFF
//#pragma config IESO = OFF
//#pragma config PWRTEN = ON
//#pragma config BOREN = OFF
//#pragma config BORV = 190
//#pragma config WDTEN = OFF
//#pragma config WDTPS = 32768
//#pragma config CCP2MX = PORTC1
//#pragma config PBADEN = OFF
//#pragma config CCP3MX = PORTB5
//#pragma config HFOFST = OFF
//#pragma config T3CMX = PORTC0
//#pragma config P2BMX = PORTB5
//#pragma config MCLRE = EXTMCLR
//#pragma config STVREN = OFF
//#pragma config LVP = OFF
//#pragma config XINST = OFF
//#pragma config CP0 = OFF
//#pragma config CP1 = OFF
//#pragma config CP2 = OFF
//#pragma config CP3 = OFF
//#pragma config CPB = OFF
//#pragma config CPD = OFF
//#pragma config WRT0 = OFF
//#pragma config WRT1 = OFF
//#pragma config WRT2 = OFF
//#pragma config WRT3 = OFF
//#pragma config WRTC = OFF
//#pragma config WRTB = OFF
//#pragma config WRTD = OFF
//#pragma config EBTR0 = OFF
//#pragma config EBTR1 = OFF
//#pragma config EBTR2 = OFF
//#pragma config EBTR3 = OFF
//#pragma config EBTRB = OFF

static unsigned char vBANK01[256];
static unsigned char vBuffer[32];

near uint8_t i;
near unsigned char Temp1;
near uint16_t Wi, Wi_last;
near uint32_t Di;


void main()
{
    //Analog setting 2620
    ADCON0 = 0x00;
    ADCON1 = 0x0F;
    ////Analog setting 26k22
    //ANSELA = 0b00100000 ;		// AN4(RA5)
    //ANSELB = 0b00000000 ;
    //ANSELC = 0b00000000 ;
    
    TRISA  = 0b00100000 ;		// RA5
    TRISB  = 0b00000000 ;
    TRISC  = 0b00000000 ;
    PORTA  = 0b00000000 ;
    PORTB  = 0b00000000 ;
    PORTC  = 0b00000000 ;
    
    // C port	//1		0	0	1	0	0	0	0
    //			//RX	TX	SDO	SDI	SCK	C2	C1	C0
    TRISC = 0x90;
    
    // TXSTA	//0		0	1		0		0	1		0		0
    //			//CSRC	TX9	TXEN	SYNC	-	BRGH	TRMT	TX9D
    TXSTA = 0x24;
    
    // RCSTA	//1		0	0		1		0		0		0		0
    //			//SPEN	RX9	SREN	CREN	ADDEN	FERR	OERR	RX9D
    RCSTA = 0x90;
    
    // BAUDCON	//0			0		0		0		0		0	0	0
    //			//ABDOVF	RCIDL	RXDTP	TXCKP	BRG16	-	WUE	ABDEN
    BAUDCON = 0x00;	
    
    // SPBRG	(36.864 MHz)	
    // SPBRG = 0x13,  013H=19, 36.864/(16(1+19)) =	115.2 Kbps
    // SPBRG = 0x04,  004H=4,  36.864/(16(1+4))  =	460.8 Kbps
    // SPBRG = 0x01,  001H=1,  36.864/(16(1+1))  =	1.152 Mbps
    // SPBRG = 0x00,  000H=0,  36.864/(16(1+0))  =	2.304 Mbps
    SPBRG = 0x00;
    
    FXMA_CS0_TRIS =0;
    FXMA_CS0_IO=0;
    
    Wi=0;
    Wi_last=31;
    for(; ; )
    {
        if (RCSTAbits.OERR)
        {
            RCSTAbits.CREN = 0;
            Temp1 = RCREG;
            RCSTAbits.CREN = 1;
        }
        if(RCIF==1) 
        {
            vBANK01[Wi]  = RCREG;
            Wi++;
        }
        if(Wi>Wi_last) {  break;  }
   }
   
    vBuffer[0] =0x48;  // H
    vBuffer[1] =0x45;  // E
    vBuffer[2] =0x4C;  // L
    vBuffer[3] =0x4C;  // L
    vBuffer[4] =0x4F;  // O
    vBuffer[5] =0x20;  // 
    vBuffer[6] =0x50;  // P
    vBuffer[7] =0x69;  // i
    vBuffer[8] =0x20;  // 
    vBuffer[9] =0x49;  // I
    vBuffer[10]=0x6D;  // m
    vBuffer[11]=0x20;  // 
    vBuffer[12]=0x50;  // P
    vBuffer[13]=0x49;  // I
    vBuffer[14]=0x43;  // C
    vBuffer[15]=0x40;  // @
    vBuffer[16]=0x0A;  // LF
    
    Wi=0;
    Wi_last=17;
    for(; ; )
    {
        //2620
        if(TRMT==1)
        ////26k22
        //if(TXSTAbits.TRMT==1)
        {
            TXREG  =  vBuffer[Wi];
            Wi++;
        }
        if(Wi>Wi_last) {  break;  }
    }
    
    FXMA_CS0_IO=1;
    
    while(1) {
        LED_A0 = 0;
        __delay_ms(250) ;
        LED_A0 = 1;
        __delay_ms(250) ;
     }
}
```

さらに今回は、x32ビットのWindowsパソコン用のMPLAB IDEとC18でも作成しました。なんとネットに接続していない自閉症のWin7の登場です。また2620は、いにしえの秋月のAKI-PICプログラマー4の時代に使っていましたから、懐かしい顔ぶれが揃っています。お久しぶり。話がそれましたが、ここでの開発環境は、x32ビットのWindowsパソコン用の最終版のMPLAB_IDE_8_92とMPLAB_C18_3.46です。PICkit3を使います。インラインアセンブリングが散在しています。一方、XC8はC18と全く異なるので、XC8ではインラインアセンブリングを全く使いません。PICは5年ほど全く使っていなかったので、レトロなUART通信を再試行するのに、少し苦労しました。includeに必要なHardwareProfile.hとConfiguration Bitsの画面コピーも添付します。
```
// MainDemo.c     MPLAB_IDE_8_92,  MPLAB_C18_3.46,  PICkit3
#include <p18f2620.h>
//#include <p18f26k22.h>
#include <GenericTypeDefs.h>
#include <delays.h>
#include <HardwareProfile.h>

#pragma udata bank1  = 0x100
static unsigned char vBANK01[256];
#pragma udata bank2 = 0x200
static unsigned char vBuffer[32];

#pragma udata access my_access
near unsigned char Temp1;
near BYTE i;
near WORD Wi;
near DWORD Di;


#pragma code
void main(void){

	//2620
	ADCON0 = 0x00;
	ADCON1 = 0x0F;
 
	////26k22
	//ANSELA = 0b00100000 ;		// AN4(RA5)
	//ANSELB = 0b00000000 ;
	//ANSELC = 0b00000000 ;
 
	TRISA  = 0b00100000 ;		// RA5
	TRISB  = 0b00000000 ;
	TRISC  = 0b00000000 ;
	PORTA  = 0b00000000 ;
	PORTB  = 0b00000000 ;
	PORTC  = 0b00000000 ;
 
	// C port	//1		0	0	1	0	0	0	0
	//			//RX	TX	SDO	SDI	SCK	C2	C1	C0
	TRISC = 0x90;
 
	// TXSTA	//0		0	1		0		0	1		0		0
	//			//CSRC	TX9	TXEN	SYNC	-	BRGH	TRMT	TX9D
	TXSTA = 0x24;
 
	// RCSTA	//1		0	0		1		0		0		0		0
	//			//SPEN	RX9	SREN	CREN	ADDEN	FERR	OERR	RX9D
	RCSTA = 0x90;
 
	// BAUDCON	//0			0		0		0		0		0	0	0
	//			//ABDOVF	RCIDL	RXDTP	TXCKP	BRG16	-	WUE	ABDEN
	BAUDCON = 0x00;	
 
	// SPBRG	(36.864 MHz)	
	// SPBRG = 0x13,  013H=19, 36.864/(16(1+19)) =	115.2 Kbps
	// SPBRG = 0x04,  004H=4,  36.864/(16(1+4))  =	460.8 Kbps
	// SPBRG = 0x01,  001H=1,  36.864/(16(1+1))  =	1.152 Mbps
	// SPBRG = 0x00,  000H=0,  36.864/(16(1+0))  =	2.304 Mbps
	SPBRG = 0x00;
 
	LED0_IO = 0;
 
	FXMA_CS0_TRIS = 0;
	FXMA_CS0_IO = 0;
 
	for(Wi = 0; Wi < 32; Wi++)
	{
		if (RCSTAbits.OERR) 
		{
			RCSTAbits.CREN = 0;
			Temp1 = RCREG;
			RCSTAbits.CREN = 1;
		}
		_asm BTFSS  PIR1, 5, 0 	_endasm      // RCIF in P1R1 = 5
		_asm BRA -2	       		_endasm
		vBANK01[Wi]  = RCREG;
	}
 
	vBuffer[0] =0x48;  // H
	vBuffer[1] =0x45;  // E
	vBuffer[2] =0x4C;  // L
	vBuffer[3] =0x4C;  // L
	vBuffer[4] =0x4F;  // O
	vBuffer[5] =0x20;  // 
	vBuffer[6] =0x50;  // P
	vBuffer[7] =0x69;  // i
	vBuffer[8] =0x20;  // 
	vBuffer[9] =0x49;  // I
	vBuffer[10]=0x6D;  // m
	vBuffer[11]=0x20;  // 
	vBuffer[12]=0x50;  // P
	vBuffer[13]=0x49;  // I
	vBuffer[14]=0x43;  // C
	vBuffer[15]=0x40;  // @
	vBuffer[16]=0x0A;  // LF
 
	for(i = 0; i < 18; i++)		
	{
		_asm BTFSS TXSTA, 1, 0 _endasm      // TRMT in TXSTA = 1
		_asm BRA   -2	       _endasm
		TXREG  =  vBuffer[i];
	}
 
	FXMA_CS0_IO = 1;
 
	while(1){
		LED0_IO = 0;
		Delay10KTCYx(250);
		LED0_IO = 1;
		Delay10KTCYx(250);
	}		
}
#pragma tmpdata
```

C18用のHardwareProfile.hです。
```
// HardwareProfile.h         MPLAB_IDE_8_92,  MPLAB_C18_3.46
#ifndef __HARDWARE_PROFILE_H
#define __HARDWARE_PROFILE_H
// Clock frequency value.  This value is used to calculate Tick Counter value
	#define GetSystemClock()		(36864000ul)		// 9.216MHz  Crystal,  PLL x4
	#define GetInstructionClock()	(GetSystemClock()/4)
	#define GetPeripheralClock()	GetInstructionClock()
// IO pins
	#define 	LED0_TRIS		(TRISAbits.TRISA0)	// LED
	#define 	LED0_IO			(LATAbits.LATA0)
	#define 	FXMA_CS0_TRIS	(TRISCbits.TRISC0)	// fxma OE
	#define 	FXMA_CS0_IO		(LATCbits.LATC0)
#endif
```
C18用2620のConfiguration Bitsの画面コピーです。
![1-5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3970076/d7bef9c0-f615-84b5-b756-46098d26d340.png)

C18用26K22のConfiguration Bitsの画面コピーです。
![Configuration Bits PIC18F26K22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3970076/4300a2bd-57cf-11ed-7f92-586563e2612d.png)
＊PICへの書き込み ：　PIC18F2620の場合、AKI-PICプログラマー Ver.4 [Win7] でも、hexファイルを書き込むことが可能です。（26k22は対応していないのでPICkit３が必要です。メルカリに時々Microchipのロゴがある正規品を見かけます。5千円前後です。Microchip自体はPICkit３の販売を終了しています。PICkit５は販売中。）　hexファイルは、MPLAB IDEの場合、 Project ＞ Build All で、プロジェクトフォルダーへ書き出されています。XIDEの場合、Production ＞ Clean and Build Main Projectで、プロジェクトフォルダー(.X)＞dist ＞default ＞productionフォルダ へ書き出されています。

次回は、今回は確認できなかったPICが受信した文字を、キャラクターlcdに表示します。