- PVSM.RU - https://www.pvsm.ru -
Прошло чуть больше месяца с тех пор, как я портировал open source модуль UART16550 на шину AHB-Lite. Писать об этом на тот момент было несколько не логично, так как еще не была опубликована статья про прерывания MIPSfpga.
Если вы опытный разработчик, то для вас только одна полезная новость: UART16550 добавлен в состав системы MIPSfpga-plus, дальше можете не читать. А тем, кого интересует разобранный пример использования этого модуля — добро пожаловать под кат.
Предполагается, что читатель:
История появления этой микросхемы неплохо описана в [L5 [5]], найти документацию на нее можно в google [L6 [6]], для нас важно другое:
module mfp_ahb_lite_uart16550(
//ABB-Lite side
input HCLK,
input HRESETn,
input [ 31 : 0 ] HADDR,
input [ 2 : 0 ] HBURST,
input HMASTLOCK, // ignored
input [ 3 : 0 ] HPROT, // ignored
input HSEL,
input [ 2 : 0 ] HSIZE,
input [ 1 : 0 ] HTRANS,
input [ 31 : 0 ] HWDATA,
input HWRITE,
output reg [ 31 : 0 ] HRDATA,
output HREADY,
output HRESP,
input SI_Endian, // ignored
//UART side
input UART_SRX, // UART serial input signal
output UART_STX, // UART serial output signal
output UART_RTS, // UART MODEM Request To Send
input UART_CTS, // UART MODEM Clear To Send
output UART_DTR, // UART MODEM Data Terminal Ready
input UART_DSR, // UART MODEM Data Set Ready
input UART_RI, // UART MODEM Ring Indicator
input UART_DCD, // UART MODEM Data Carrier Detect
//UART internal
output UART_BAUD, // UART baudrate output
output UART_INT // UART interrupt
);
parameter S_INIT = 0,
S_IDLE = 1,
S_READ = 2,
S_WRITE = 3;
reg [ 1:0 ] State, Next;
assign HRESP = 1'b0;
assign HREADY = (State == S_IDLE);
always @ (posedge HCLK) begin
if (~HRESETn)
State <= S_INIT;
else
State <= Next;
end
reg [ 2:0 ] ADDR_old;
wire [ 2:0 ] ADDR = HADDR [ 4:2 ];
wire [ 7:0 ] ReadData;
parameter HTRANS_IDLE = 2'b0;
wire NeedAction = HTRANS != HTRANS_IDLE && HSEL;
always @ (*) begin
//State change decision
case(State)
default : Next = S_IDLE;
S_IDLE : Next = ~NeedAction ? S_IDLE : (
HWRITE ? S_WRITE : S_READ );
endcase
end
always @ (posedge HCLK) begin
case(State)
S_INIT : ;
S_IDLE : if(HSEL) ADDR_old <= ADDR;
S_READ : HRDATA <= { 24'b0, ReadData};
S_WRITE : ;
endcase
end
wire [ 7:0 ] WriteData = HWDATA [ 7:0 ];
wire [ 2:0 ] ActionAddr;
wire WriteAction;
wire ReadAction;
reg [ 10:0 ] conf;
assign { ReadAction, WriteAction, ActionAddr } = conf;
always @ (*) begin
//io
case(State)
default : conf = { 2'b00, 8'b0 };
S_READ : conf = { 2'b10, ADDR };
S_WRITE : conf = { 2'b01, ADDR_old };
endcase
end
// Registers
uart_regs regs(
.clk ( HCLK ),
.wb_rst_i ( ~HRESETn ),
.wb_addr_i ( ActionAddr ),
.wb_dat_i ( WriteData ),
.wb_dat_o ( ReadData ),
.wb_we_i ( WriteAction ),
.wb_re_i ( ReadAction ),
.modem_inputs ( { UART_CTS, UART_DSR, UART_RI, UART_DCD } ),
.stx_pad_o ( UART_STX ),
.srx_pad_i ( UART_SRX ),
.rts_pad_o ( UART_RTS ),
.dtr_pad_o ( UART_DTR ),
.int_o ( UART_INT ),
.baud_o ( UART_BAUD )
);
endmodule
проверить, что в файле mfp_ahb_lite_matrix_config.vh установлена следующая настройка [S3 [12]]:
`define MFP_USE_DUPLEX_UART
в файле main.c установить [S10 [23]]:
#define RUNTYPE SIMULATION
выполнить сборку программы и ее запуск в симуляторе:
02_compile_and_link.bat
05_generate_verilog_readmemh_file.bat
06_simulate_with_modelsim.bat
при запуске производится настройка UART16550 [S12 [25]]:
void uartInit(uint16_t divisor)
{
// 8n1 uart mode
MFP_UART_LCR = MFP_UART_LCR_8N1;
// Divisor Latches access enable
MFP_UART_LCR |= MFP_UART_LCR_LATCH;
// Divisor LSB
MFP_UART_DLL = divisor & 0xFF;
// Divisor MSB
MFP_UART_DLH = (divisor >> 8) & 0xff;
// Divisor Latches access disable
MFP_UART_LCR &= ~MFP_UART_LCR_LATCH;
//enable Received Data available interrupt
MFP_UART_IER = MFP_UART_IER_RDA;
//set 4 byte Receiver FIFO Interrupt trigger level
MFP_UART_FCR = MFP_UART_FCR_ITL4;
}
настройка прерываний [S13 [26]] (детально разобрана в [L12 [27]]):
void mipsInterruptInit(void)
{
// Status.BEV 0 - vector interrupt mode
mips32_bicsr (SR_BEV);
// Cause.IV, 1 - special int vector (0x200)
// where 0x200 - base for others interrupts;
mips32_biscr (CR_IV);
// get IntCtl reg value
uint32_t intCtl = mips32_getintctl();
// set interrupt table vector spacing (0x20 in our case)
// see exceptions.S for details
mips32_setintctl(intCtl | INTCTL_VS_32);
// interrupt enable, HW3 unmasked
mips32_bissr (SR_IE | SR_HINT3);
}
обработка прерывания предполагает проверку того, что оно вызвано именно наличием данных во входящем FIFO [S14 [28]]:
// uart interrupt handler
void __attribute__ ((interrupt, keep_interrupts_masked)) __mips_isr_hw3 ()
{
// Receiver Data available interrupt handler
if(MFP_UART_IIR & MFP_UART_IIR_RDA)
uartReceive();
}
после чего следует их чтение (до тех пор, пока FIFO не опустеет) и вывод [S15 [29]]:
void uartReceive(void)
{
// is there something in receiver fifo?
while (MFP_UART_LSR & MFP_UART_LSR_DR)
{
// data receive
uint8_t data = MFP_UART_RXR;
receivedDataOutput(data);
#if RUNTYPE == HARDWARE
uartTransmit(data);
#endif
}
}
void uartTransmit(uint8_t data)
{
// waiting for transmitter fifo empty
while (!(MFP_UART_LSR & MFP_UART_LSR_TFE));
// data transmit
MFP_UART_TXR = data;
}
ниже представлен результат работы программы. Так как при настройке модуля мы выставили режим срабатывания прерывания после приема 4х символов, то передача на время прерывается для приема. Оставшиеся символы получены нами после еще одного такого же прерывания, но которое уже было вызвано не наличием 4х символов в очереди, а не пустой очередью и таймаутом (контроллер понял, что больше символов не будет и сообщил, что очередь не пустая);
для программы 05_uart прием выполняется уже после завершения передачи, все это время принятые данные ждут в FIFO приемника:
Автор выражает благодарность коллективу переводчиков [1] учебника Дэвида Харриса и Сары Харрис «Цифровая схемотехника и архитектура компьютера», компании Imagination Technologies [31] за академическую лицензию на современное процессорное ядро и персонально Юрию Панчулу YuriPanchul [32] за его работу по популяризации MIPSfpga.
[L1] — Цифровая схемотехника и архитектура компьютера [1];
[L2] — Как начать работать с MIPSfpga [2];
[L3] — Проект MIPSfpga-plus на github [3];
[L4] — Wikipedia: UART [4];
[L5] — Wikipedia: UART16550 [5];
[L6] — Google: UART16550 [6];
[L7] — Проект freecores/uart16550 [7];
[L8] — Проект olofk/uart16550 [8];
[L9] — Проект opencores/UART 16550 core [9];
[L10] -FPGA плата Terasic DE10-Lite [17];
[L11] — Проект ahb_lite_uart16550 [20];
[L12] — MIPSfpga и прерывания [27];
[D1] — UART IP Core Specification [21];
[D2] — MIPS32 microAptiv UP Processor Core AHB-Lite Interface [22];
[P1] — Работа примера на отладочной плате [33];
[P2] — Работа в режиме обработки прерывания UART [34];
[P3] — Работа путем периодического опроса регистра [35];
[S1] — Модуль mfp_ahb_lite_uart16550 [10];
[S2] — Каталог mipsfpga-plus/uart16550 [11];
[S3] — Опция MFP_USE_DUPLEX_UART [12];
[S4] — Сигналы UART_SRX и UART_STX [13];
[S5] — Интерфейс управления модемом [14];
[S6] — Подключение сигнала прерывания [15];
[S7] — Сигналы UART в режиме симуляции [16];
[S8] — Пример использования '05_uart' [18];
[S9] — Пример использования '08_uart_irq' [19];
[S10] — Настройка режима работы программы-примера [23];
[S11] — Заголовочный файл uart16550.h [24];
[S12] — Программная настройка UART16550 [25];
[S13] — Настройка прерываний [26];
[S14] — Обработка прерывания UART [28];
[S15] — Чтение полученных данных UART [29];
[S16] — Обратная отправка принятых данных [30];
Автор: Stanislav Zhelnio
Источник [36]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/verilog/251312
Ссылки в тексте:
[1] L1: https://habrahabr.ru/post/259505/
[2] L2: https://habrahabr.ru/post/275215/
[3] L3: https://github.com/MIPSfpga/mipsfpga-plus
[4] L4: https://ru.wikipedia.org/wiki/%D0%A3%D0%BD%D0%B8%D0%B2%D0%B5%D1%80%D1%81%D0%B0%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%B0%D1%81%D0%B8%D0%BD%D1%85%D1%80%D0%BE%D0%BD%D0%BD%D1%8B%D0%B9_%D0%BF%D1%80%D0%B8%D1%91%D0%BC%D0%BE%D0%BF%D0%B5%D1%80%D0%B5%D0%B4%D0%B0%D1%82%D1%87%D0%B8%D0%BA
[5] L5: https://ru.wikipedia.org/wiki/16550_UART
[6] L6: https://www.google.ru/search?q=uart+16550+datasheet+file%3Apdf
[7] L7: https://github.com/freecores/uart16550
[8] L8: https://github.com/olofk/uart16550
[9] L9: http://opencores.org/project,uart16550
[10] S1: https://github.com/MIPSfpga/mipsfpga-plus/blob/5169e133ea2de692e8f9564896f46844ec5bb398/mfp_ahb_lite_uart16550.v
[11] S2: https://github.com/MIPSfpga/mipsfpga-plus/tree/5169e133ea2de692e8f9564896f46844ec5bb398/uart16550
[12] S3: https://github.com/MIPSfpga/mipsfpga-plus/blob/5169e133ea2de692e8f9564896f46844ec5bb398/mfp_ahb_lite_matrix_config.vh#L21
[13] S4: https://github.com/MIPSfpga/mipsfpga-plus/blob/5169e133ea2de692e8f9564896f46844ec5bb398/mfp_ahb_lite_matrix_with_loader.v#L178-L185
[14] S5: https://github.com/MIPSfpga/mipsfpga-plus/blob/5169e133ea2de692e8f9564896f46844ec5bb398/mfp_ahb_lite_matrix.v#L189-L196
[15] S6: https://github.com/MIPSfpga/mipsfpga-plus/blob/5169e133ea2de692e8f9564896f46844ec5bb398/mfp_system.v#L376-L385
[16] S7: https://github.com/MIPSfpga/mipsfpga-plus/blob/5169e133ea2de692e8f9564896f46844ec5bb398/mfp_testbench.v#L51-L54
[17] L10: http://de10-lite.terasic.com/
[18] S8: https://github.com/MIPSfpga/mipsfpga-plus/tree/5169e133ea2de692e8f9564896f46844ec5bb398/programs/05_uart
[19] S9: https://github.com/MIPSfpga/mipsfpga-plus/tree/5169e133ea2de692e8f9564896f46844ec5bb398/programs/08_uart_irq
[20] L11: https://github.com/zhelnio/ahb_lite_uart16550
[21] D1: https://github.com/MIPSfpga/mipsfpga-plus/blob/5169e133ea2de692e8f9564896f46844ec5bb398/documentation/peripherals/UART_spec.pdf
[22] D2: https://github.com/zhelnio/memos/blob/master/public/02_mips_uart/doc/D2_MicroAptiv_UP_AHB_Lite_Interface_MD01082.pdf
[23] S10: https://github.com/MIPSfpga/mipsfpga-plus/blob/5169e133ea2de692e8f9564896f46844ec5bb398/programs/08_uart_irq/main.c#L12
[24] S11: https://github.com/MIPSfpga/mipsfpga-plus/blob/5169e133ea2de692e8f9564896f46844ec5bb398/programs/08_uart_irq/uart16550.h
[25] S12: https://github.com/MIPSfpga/mipsfpga-plus/blob/5169e133ea2de692e8f9564896f46844ec5bb398/programs/08_uart_irq/main.c#L27-L37
[26] S13: https://github.com/MIPSfpga/mipsfpga-plus/blob/5169e133ea2de692e8f9564896f46844ec5bb398/programs/08_uart_irq/main.c#L65-L76
[27] L12: https://habrahabr.ru/post/324900/
[28] S14: https://github.com/MIPSfpga/mipsfpga-plus/blob/5169e133ea2de692e8f9564896f46844ec5bb398/programs/08_uart_irq/main.c#L78-L84
[29] S15: https://github.com/MIPSfpga/mipsfpga-plus/blob/5169e133ea2de692e8f9564896f46844ec5bb398/programs/08_uart_irq/main.c#L52-L63
[30] S16: https://github.com/MIPSfpga/mipsfpga-plus/blob/5169e133ea2de692e8f9564896f46844ec5bb398/programs/08_uart_irq/main.c#L59-L61
[31] Imagination Technologies: https://www.imgtec.com/
[32] YuriPanchul: https://habrahabr.ru/users/yuripanchul/
[33] Работа примера на отладочной плате: https://raw.githubusercontent.com/zhelnio/memos/master/public/02_mips_uart/doc/P1_work_on_hw.gif
[34] Работа в режиме обработки прерывания UART: https://raw.githubusercontent.com/zhelnio/memos/master/public/02_mips_uart/doc/P2_signals_uart_irq.png
[35] Работа путем периодического опроса регистра: https://raw.githubusercontent.com/zhelnio/memos/master/public/02_mips_uart/doc/P3_signals_uart.png
[36] Источник: https://habrahabr.ru/post/325168/
Нажмите здесь для печати.