/* * TOPPERS/SSP Kernel * Toyohashi Open Platform for Embedded Real-Time Systems/ * Advanced Standard Profile Kernel * * Copyright (C) 2007 by Embedded and Real-Time Systems Laboratory * Graduate School of Information Science, Nagoya Univ., JAPAN * Copyright (C) 2012 by Meika Sugimoto * Copyright (C) 2015, 2019 by Naoki Saito * Nagoya Municipal Industrial Research Institute, JAPAN * * 上記著作権者は,以下の(1)〜(4)の条件を満たす場合に限り,本ソフトウェ * ア(本ソフトウェアを改変したものを含む.以下同じ)を使用・複製・改 * 変・再配布(以下,利用と呼ぶ)することを無償で許諾する. * (1) 本ソフトウェアをソースコードの形で利用する場合には,上記の著作 * 権表示,この利用条件および下記の無保証規定が,そのままの形でソー * スコード中に含まれていること. * (2) 本ソフトウェアを,ライブラリ形式など,他のソフトウェア開発に使 * 用できる形で再配布する場合には,再配布に伴うドキュメント(利用 * 者マニュアルなど)に,上記の著作権表示,この利用条件および下記 * の無保証規定を掲載すること. * (3) 本ソフトウェアを,機器に組み込むなど,他のソフトウェア開発に使 * 用できない形で再配布する場合には,次のいずれかの条件を満たすこ * と. * (a) 再配布に伴うドキュメント(利用者マニュアルなど)に,上記の著 * 作権表示,この利用条件および下記の無保証規定を掲載すること. * (b) 再配布の形態を,別に定める方法によって,TOPPERSプロジェクトに * 報告すること. * (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損 * 害からも,上記著作権者およびTOPPERSプロジェクトを免責すること. * また,本ソフトウェアのユーザまたはエンドユーザからのいかなる理 * 由に基づく請求からも,上記著作権者およびTOPPERSプロジェクトを * 免責すること. * * 本ソフトウェアは,無保証で提供されているものである.上記著作権者お * よびTOPPERSプロジェクトは,本ソフトウェアに関して,特定の使用目的 * に対する適合性も含めて,いかなる保証も行わない.また,本ソフトウェ * アの利用により直接的または間接的に生じたいかなる損害に関しても,そ * の責任を負わない. * */ /* * シリアルドライバ */ #include #include "target_serial.h" #include "target_syssvc.h" #include "pl011.h" #include "bcm2837.h" /* * レジスタ設定値 */ #define PORT2SIOPID(x) ((x) + 1) #define INDEX_PORT(x) ((x) - 1) #define GET_SIOPCB(x) (&siopcb_table[INDEX_PORT(x)]) const SIOPINIB siopinib_table[TNUM_PORT] = { { RPI_UART0_BASE, /* baseAddress */ RPI_UART_IBRD_115200, /* ibrd */ RPI_UART_FBRD_115200, /* fbrd */ UART_LCR_H_WLEN8, /* lcr_h */ }, }; SIOPCB siopcb_table[TNUM_PORT]; /* * 送信バッファに空きがあるか? */ Inline bool_t sio_putready(SIOPCB* siopcb) { return((sil_rew_mem(UART_FR(siopcb->inib->baseAddress)) & UART_FR_TXFF) == 0U); } /* * 受信バッファに文字があるか? */ Inline bool_t sio_getready(SIOPCB* siopcb) { return((sil_rew_mem(UART_FR(siopcb->inib->baseAddress)) & UART_FR_RXFE) == 0U); } /* * 受信した文字の取出し */ Inline char sio_getchar(SIOPCB *siopcb) { return((char) sil_rew_mem(UART_DR(siopcb->inib->baseAddress))); } /* * 送信する文字の書込み */ Inline void sio_putchar(SIOPCB *siopcb, char c) { sil_wrw_mem(UART_DR(siopcb->inib->baseAddress), (uint32_t) c); } /* * ターゲットのシリアル初期化 */ void target_low_output_init(ID siopid) { SIOPINIB *inib; volatile uint32_t __attribute__((aligned(16))) mbox[36]; inib = &siopinib_table[INDEX_PORT(siopid)]; /* * disable UART */ sil_wrw_mem(UART_CR(inib->baseAddress), 0U); // クロックのセットアップ mbox[0] = 9*4; mbox[1] = MBOX_REQUEST; mbox[2] = MBOX_TAG_SETCLKRATE; mbox[3] = 12; mbox[4] = 8; mbox[5] = 2; mbox[6] = 4000000; // 4MHz mbox[7] = 0; mbox[8] = MBOX_TAG_LAST; mbox_call(MBOX_CH_PROP, mbox); /* * clear error flag */ sil_wrw_mem(UART_ECR(inib->baseAddress), 0U); /* * clear interrupt status */ sil_wrw_mem(UART_ICR(inib->baseAddress), 0U); sil_wrw_mem(UART_RIS(inib->baseAddress), 0U); sil_wrw_mem(UART_MIS(inib->baseAddress), 0U); /* * configure UART */ sil_wrw_mem(UART_IBRD(inib->baseAddress), inib->ibrd); sil_wrw_mem(UART_FBRD(inib->baseAddress), inib->fbrd); sil_wrw_mem(UART_LCR_H(inib->baseAddress), inib->lcr_h); /* * enable UART */ sil_wrw_mem(UART_CR(inib->baseAddress), UART_CR_UARTEN|UART_CR_TXE|UART_CR_RXE); } /* * SIO初期化 */ void sio_initialize(intptr_t exinf) { int i; for (i = 0; i < TNUM_PORT; i++) { siopcb_table[i].inib = &(siopinib_table[i]); siopcb_table[i].exinf = 0; } } /* * シリアルオープン */ SIOPCB *sio_opn_por(ID siopid, intptr_t exinf) { SIOPCB* siopcb; if (siopid > TNUM_PORT) { return NULL; } siopcb = GET_SIOPCB(siopid); siopcb->exinf = exinf; target_low_output_init(siopid); // 受信コールバック許可 sio_ena_cbr(siopcb, SIO_RDY_RCV); return siopcb; } /* * シリアルクローズ */ void sio_cls_por(SIOPCB *siopcb) { /* * UARTをディスエーブル */ sil_wrw_mem(UART_CR(siopcb->inib->baseAddress), 0U); } /* * 割込みハンドラ */ #include "target_syssvc.h" void sio_isr(intptr_t exinf) { SIOPCB* siopcb = GET_SIOPCB(exinf); if (sio_getready(siopcb)) { /* * 受信通知コールバックルーチンを呼び出す. */ sio_irdy_rcv(siopcb->exinf); } if (sio_putready(siopcb)) { /* * 送信可能コールバックルーチンを呼び出す. */ sio_irdy_snd(siopcb->exinf); } } /* * 1文字送信 */ bool_t sio_snd_chr(SIOPCB *siopcb, char c) { if (sio_putready(siopcb)){ sio_putchar(siopcb, c); return(true); } return(false); } /* * 1文字受信 */ int_t sio_rcv_chr(SIOPCB *siopcb) { if (sio_getready(siopcb)) { return((int_t)(uint8_t) sio_getchar(siopcb)); } return(-1); } /* * コールバックの許可 */ void sio_ena_cbr(SIOPCB *siopcb, uint_t cbrtn) { SIOPINIB *inib; uint32_t reg; inib = siopcb->inib; reg = sil_rew_mem(UART_IMSC(inib->baseAddress)); switch (cbrtn) { case SIO_RDY_SND: reg |= UART_IMSC_TXIM; break; case SIO_RDY_RCV: reg |= UART_IMSC_RXIM; break; } sil_wrw_mem(UART_IMSC(inib->baseAddress), reg); } /* * コールバックの禁止 */ void sio_dis_cbr(SIOPCB *siopcb, uint_t cbrtn) { SIOPINIB *inib; uint32_t reg; inib = siopcb -> inib; reg = sil_rew_mem(UART_IMSC(inib->baseAddress)); switch (cbrtn) { case SIO_RDY_SND: reg &= ~UART_IMSC_TXIM; break; case SIO_RDY_RCV: reg &= ~UART_IMSC_RXIM; break; } sil_wrw_mem(UART_IMSC(inib->baseAddress), reg); } /* * 1文字出力(ポーリングでの出力) */ void sio_pol_snd_chr(char c, ID siopid) { SIOPCB *siopcb = GET_SIOPCB(siopid); if(c == '\n'){ while(!sio_snd_chr(siopcb, '\r')); } while(!sio_snd_chr(siopcb, c)); }