FPGA, SoC, And CPLD Boards And Kits
FPGA Evaluation and Development Kits
6021 Discussions

Agilex-7 SoC Uart Driver ForBaremetal App

Balerion
Novice
869 Views

Hi,

I am trying to develope a baremetal Uart driver for Agilex-7 SoC. While I was reading the "Agilex™ 7 Hard Processor System Technical Reference Manual" I couldn't figure out what to do to transfer data and receive data from uart peripheral step by step. I mean in a sequence what should I do? I coudn't understand that. I saw in the document that, first I need to enable the clock for Uart peripheral by writing 1 to the "l4spclken" field but then what to do to? Could you please help me?

 

Thanks,

Balerion

Labels (1)
0 Kudos
13 Replies
Balerion
Novice
829 Views

Hi again,

If there is a linux uart driver for this device, can you share that with me? So that I can take it as a base reference to write my own baremetal uart driver?

 

Thanks,

Balerion

0 Kudos
JingyangTeh
Employee
779 Views

Hi Balerion


There is no UART Driver for baremetal app for the agilex7.

However you could add the uart into the device tree and access the uart using the linux filesystem.

You could find the example on interfacing with the uart with our Agilex7 GSRD

https://www.rocketboards.org/foswiki/Documentation/AgilexSoCGSRD


Regards

Jingyang, Teh


0 Kudos
Balerion
Novice
772 Views

Hi Jingyang, Teh

I found out at another post of mine on the forum that there is no BSP support for baremetal application on Agilex-7. However, I want to develop a simple uart app and I don't want to use linux. In this case, I guess I need to write my own uart driver. I take Agilex-7 HPS Technical reference manual for my guidance. But I don't really find detailed information about how to make Uart Controller functional. What should I do step by step in order to develop one? Could you help about that?

 

Regards,

Balerion 

0 Kudos
JingyangTeh
Employee
684 Views

HI Balerion


Sorry there is no step by step on the creation.

You could refer to how it was done for the older device which supports baremetal.

The intel-hwlibs library was used previously for baremetal application.


e.g.

There is a main file hps.h for each device family which maps the address to the register map.(Try searching for hps.h)

https://www.intel.com/content/www/us/en/programmable/hps/cyclone-v/hps.html

You could try mapping the peripheral address to the one of Agilex7 base on its register map.

https://www.intel.com/content/www/us/en/programmable/hps/agilex7/hps.html


Regards

Jingyang, Teh





0 Kudos
JingyangTeh
Employee
590 Views

Hi


Any update on this case?


Regards

Jingyang, Teh


0 Kudos
Balerion
Novice
575 Views

Hi Jingyang,

I have found some files for Arria 10 SoC(hps.h, socal.h, alt_uart.h, alt_printf.h, alt_16550_uart.h, alt_printf.c, alt_p2uart.c) in SoCEDS Pro directory which I've downloaded previously. I also checked that whether the uart registers of Arria 10 SoC is similar to Agilex-7 SoC and saw that they are the same. I'll try to use these files. I'm also in touch with Altera through the distributor of my board. It is up to you to close this post or not. Thanks for your support.

 

Regards,

Balerion

0 Kudos
JingyangTeh
Employee
487 Views

Hi


Since this thread been resolve, I shall set this thread to close pending. If you still need further assistance, you are welcome to reopen this thread within 20days or open a new thread, some one will be right with you. Please login to ‘https://supporttickets.intel.com’, view details of the desire request, and post a feed/response within the next 15 days to allow me to continue to support you. After 15 days, this thread will be transitioned to community support. The community users will be able to help you on your follow-up questions.


If you happened to close this thread you might receive a survey. If you think you would rank your support experience less than 4 out of 10, please allow me to correct it before closing or if the problem can’t be corrected, please let me know the cause so that I may improve your future service experience.


Regards

Jingyang, Teh


0 Kudos
Kiebach
Novice
401 Views

Hi Balerion,

The trick is figuring out the same register address FIFO is used for input AND output.

I did it like this:

#define REG(addr) (*((volatile uint32_t * const)(addr)))

#define ADDR_UART0 0xFFC02000

#define ADDR_UART0_RBR ((ADDR_UART0) + 0x0 ) // RO 0x00000000 Receive Buffer Register, LCR->DLAB=0
#define ADDR_UART0_THR ((ADDR_UART0) + 0x0 ) // WO 0x00000000 Transmit Holding Register, LCR->DLAB=1
#define ADDR_UART0_IER ((ADDR_UART0) + 0x4 ) // RW 0x00000000 Interrupt Enable Register
#define ADDR_UART0_IIR ((ADDR_UART0) + 0x8 ) // RO 0x00000001 Interrupt Identification Register
#define ADDR_UART0_LCR ((ADDR_UART0) + 0xC ) // RW 0x00000000 Line Control Register
#define ADDR_UART0_MCR ((ADDR_UART0) + 0x10) // RW 0x00000000 Modem Control Register
#define ADDR_UART0_LSR ((ADDR_UART0) + 0x14) // RO 0x00000060 Line Status Register
#define ADDR_UART0_MSR ((ADDR_UART0) + 0x18) // RO 0x00000000 Modem Status Register
#define ADDR_UART0_SCR ((ADDR_UART0) + 0x1C) // RW 0x00000000 Scratchpad Register
#define ADDR_UART0_SRBR0 ((ADDR_UART0) + 0x30) // RO 0x00000000 Shadow Receive Buffer Register
#define ADDR_UART0_SRBR1 ((ADDR_UART0) + 0x34) // RO 0x00000000 Shadow Receive Buffer Register 1
#define ADDR_UART0_SRBR2 ((ADDR_UART0) + 0x38) // RO 0x00000000 Shadow Receive Buffer Register 2
#define ADDR_UART0_SRBR3 ((ADDR_UART0) + 0x3C) // RO 0x00000000 Shadow Receive Buffer Register 3
#define ADDR_UART0_SRBR4 ((ADDR_UART0) + 0x40) // RO 0x00000000 Shadow Receive Buffer Register 4
#define ADDR_UART0_SRBR5 ((ADDR_UART0) + 0x44) // RO 0x00000000 Shadow Receive Buffer Register 5
#define ADDR_UART0_SRBR6 ((ADDR_UART0) + 0x48) // RO 0x00000000 Shadow Receive Buffer Register 6
#define ADDR_UART0_SRBR7 ((ADDR_UART0) + 0x4C) // RO 0x00000000 Shadow Receive Buffer Register 7
#define ADDR_UART0_SRBR8 ((ADDR_UART0) + 0x50) // RO 0x00000000 Shadow Receive Buffer Register 8
#define ADDR_UART0_SRBR9 ((ADDR_UART0) + 0x54) // RO 0x00000000 Shadow Receive Buffer Register 9
#define ADDR_UART0_SRBR10 ((ADDR_UART0) + 0x58) // RO 0x00000000 Shadow Receive Buffer Register 10
#define ADDR_UART0_SRBR11 ((ADDR_UART0) + 0x5C) // RO 0x00000000 Shadow Receive Buffer Register 11
#define ADDR_UART0_SRBR12 ((ADDR_UART0) + 0x60) // RO 0x00000000 Shadow Receive Buffer Register 12
#define ADDR_UART0_SRBR13 ((ADDR_UART0) + 0x64) // RO 0x00000000 Shadow Receive Buffer Register 13
#define ADDR_UART0_SRBR14 ((ADDR_UART0) + 0x68) // RO 0x00000000 Shadow Receive Buffer Register 14
#define ADDR_UART0_SRBR15 ((ADDR_UART0) + 0x6C) // RO 0x00000000 Shadow Receive Buffer Register 15
#define ADDR_UART0_FAR ((ADDR_UART0) + 0x70) // RW 0x00000000 FIFO Access Register
#define ADDR_UART0_TFR ((ADDR_UART0) + 0x74) // RO 0x00000000 Transmit FIFO Read
#define ADDR_UART0_RFW ((ADDR_UART0) + 0x78) // RW 0x00000000 Receive FIFO Write
#define ADDR_UART0_USR ((ADDR_UART0) + 0x7C) // RO 0x00000006 UART Status register
#define ADDR_UART0_TFL ((ADDR_UART0) + 0x80) // RO 0x00000000 Transmit FIFO Level
#define ADDR_UART0_RFL ((ADDR_UART0) + 0x84) // RO 0x00000000 Receive FIFO Level
#define ADDR_UART0_SRR ((ADDR_UART0) + 0x88) // RW 0x00000000 Software Reset Register
#define ADDR_UART0_SRTS ((ADDR_UART0) + 0x8C) // RW 0x0000000 Shadow Request to Send
#define ADDR_UART0_SBCR ((ADDR_UART0) + 0x90) // RW 0x00000000 Shadow Break Control Register
#define ADDR_UART0_SDMAM ((ADDR_UART0) + 0x94) // RW 0x00000000 Shadow DMA Mode
#define ADDR_UART0_SFE ((ADDR_UART0) + 0x98) // RW 0x00000000 Shadow FIFO Enable
#define ADDR_UART0_SRT ((ADDR_UART0) + 0x9C) // RW 0x00000000 Shadow RCVR Trigger
#define ADDR_UART0_STET ((ADDR_UART0) + 0xA0) // RW 0x00000000 Shadow TX Empty Trigger
#define ADDR_UART0_HTX ((ADDR_UART0) + 0xA4) // RW 0x00000000 Halt TX
#define ADDR_UART0_DMASA ((ADDR_UART0) + 0xA8) // RW 0x00000000 DMA Software Acknowledge
#define ADDR_UART0_CPR ((ADDR_UART0) + 0xF4) // RO 0x00083F32 Component Parameter Register
#define ADDR_UART0_UCV ((ADDR_UART0) + 0xF8) // RO 0x3331352A Component Version
#define ADDR_UART0_CTR ((ADDR_UART0) + 0xFC) // RO 0x44570110 Component Type Register


#define UART_USR_BUSY 0x01
#define UART_USR_TFNF 0x02 // tx fifo not full
#define UART_USR_TFE 0x04 // tx fifo empty
#define UART_USR_RFNE 0x08 // rx fifo not empty
#define UART_USR_RFF 0x10 // rx fifo full
#define UART_LSR_DR 0x01 // rx data ready
#define uart_IsTransmitFull() ((REG(ADDR_UART0_USR) & (uint32_t)UART_USR_TFNF) != (uint32_t)UART_USR_TFNF)
#define uart_IsTransmitEmpty() ((REG(ADDR_UART0_USR) & (uint32_t)UART_USR_TFE) == (uint32_t)UART_USR_TFE)
#define uart_IsReceiveData() ((REG(ADDR_UART0_USR) & (uint32_t)UART_USR_RFNE) == (uint32_t)UART_USR_RFNE)
//#define uart_IsReceiveData() ((REG(ADDR_UART0_LSR) & (uint32_t)UART_LSR_DR) == (uint32_t)UART_LSR_DR)
#define uart_rx_byte() REG(ADDR_UART0_RBR)
#define uart_tx_byte() REG(ADDR_UART0_THR)

void uart0_init(void)
{
uint32_t reg;

// disable the FIFO's
reg = REG(ADDR_UART0_IIR);
reg &= ~0xC0;
REG(ADDR_UART0_IIR) = reg;

// enable the FIFO's
reg = REG(ADDR_UART0_IIR);
reg |= 0xC0;
REG(ADDR_UART0_IIR) = reg;
}

void outbyte(uint8_t data)
{
// wait until tx fifo is not full
while (uart_IsTransmitFull());
uart_tx_byte() = ((uint32_t)data);
}

void printz(const char *str)
{
//while (*str != (uint32_t)NULL)
while (*str != '\0')
{
if (*str == '\n')
{
outbyte((uint8_t)('\r'));
}
outbyte((uint8_t)(*str));
str ++;
}

return;
}

Be mindful of the WDT if you code an inbyte(). You have to clear it before it triggers or reset occurs.

Kiebach

Balerion
Novice
319 Views

Hi Kiebach,

Thanks for your answer. I want to ask a few questions about it.

  • Did you try the code you posted on Agilex-7 SoC hardware?
  • Do I need to clear Watchdog timer in each byte transmission? If so, do you know how to clear it and which WDT to clear is there only one?
  • As much as I see that your code can be used for reading in a polling way, but I want to create an interrupt-based mechanism such that when a byte is received, a uart interrupt should be triggered and then in uart isr I will take that byte into a circular buffer and handle it later. For this do you know what to do? I found that GIC (Generic Interrupt Controller) should be used for this but couldn't figure it out. 

 

Best Regards,

Balerion

 

0 Kudos
Kiebach
Novice
270 Views

Hi Balerion,

Yes, have been using this code with Agilex7 HPS.  The WDT, if not sedated will cause a reset.  I think it is set to expire after 5 or 10 seconds.  I continuously clear the WDT in my code.  It is not an efficient method.  I'm actually clearing the WDT much more often than every byte transmission.

This is how you clear the WDT:

// reset WDT
REG(ADDR_TIMER_WATCHDOG + 0xC) = 0x76;

I haven't experimented with the interrupts yet, so everything I do is polling based.  Even clearing of the WDT is in my inbyte() function.

Good Luck,

Kiebach

Balerion
Novice
254 Views

Hi Kiebach,

Thanks for your response. I will try these codes as soon as I am able to connect to my dev-kit. Currently, I'm facing a problem in Arm DS when I try to create a debug session. I can't even download and debug a simple helloWorld.axf app The debug server is started but it couldn't connect to the device. It says "The target hardware identity couldn't be verified. Please check that the target being connected to is of type Agilex-7 SoC" Have you ever faced anything like this. I am using Arm DS v2023.1.

Best Regards,

Balerion

0 Kudos
Kiebach
Novice
232 Views

Yeah the Agilex7 JTAG connection is not working.  Any solution that Intel has offered always gets bogged down in build failures due to licensing issues for IPs that are not relevant, like ethernet, for example.  So far the HPS is black box with the UART being only window into it...

0 Kudos
Balerion
Novice
208 Views

Hi again Kiebach,

Currently, you are able to work bare-metal on Agilex-7 SoC? What kind of board do you have? I am working on a dev-kit. The reason for me to ask this is to understand whether I do something wrong or not. If we are working on the same board, I wonder how you connect, download and debug your code on it.

Thanks, 

Balerion

0 Kudos
Reply