• 0

want to get user input from terminal on bare metal zedboard


Question

I stepped through this tutorial and got it to work:
http://islab.soe.uoguelph.ca/sareibi/TEACHING_dr/XILINX_VIVADO_dr/HwSw_dr/VivadoEmbeddedZyncTutorialAddIP.pdf

It's a bare metal project that does writes and reads to a simple custom AXI IP block and then prints some info and results to serial terminal. I connect to zedboard with PUTTY on my PC, and when I run the code in vitis, it dumps a bunch of info to the terminal by calling print().

My question is how do I tweak this to do serial READ from the user serial terminal, but keep everything pretty much the same?

If its complicated, could someone point me to a tutorial somewhere?

I'm using vivado 2020.1, if that makes any difference.

Thanks.

 

Link to post
Share on other sites

10 answers to this question

Recommended Posts

  • 0
2 hours ago, skinnypanda said:

My question is how do I tweak this to do serial READ from the user serial terminal, but keep everything pretty much the same?

Writing messages to a standard output using xil_printf is quite a bit different than reading user input. For one thing you have parse the user input to make sense of it. It's the same with PC applications programming. it's a big deal. What you probably want is some sort of menu loop to accept user commands. So, I seriously doubt that 'tweaking' the code that you have is going to work.

Here are a few snippets of what I'm taking about from an old project for the Eclypse-Z7:


    while(1) {
      ucmd = 0;
      ucmd = GetUserCmd();
      xil_printf("Command(%c) Mode(%d) Num(%d)\n\r", ucmd, mode, CmdValues);

//      if (ucmd == 'C') {
      switch (ucmd)
      {
        case 'C' :
          *(pcontrol) = 0x00000380; // Quescent mode
          usleep(1);

          ConfigRegs(&cfgbuff[1], (u32) 6);
          mode = cfgbuff[0];
          DisplayCtrlRegs();

          if (CmdValues > 7) {
            // Copy Message to BRAM0
            j = CmdValues-7;
            if (j > 511) j = 511;
            for (i=0; i<j; i++) {
              *(ptrBRAM0 + i) = cfgbuff[i+7];
            }

            // Initiate HDL DMA from BRAM0 to SIG_GEN freq_lut BRAM
            LoadMsg();
          }
          break;

        case 'T' :
          mode = cfgbuff[0];
          ConfigRegs(&cfgbuff[1], (u32) 6);
          DisplayCtrlRegs();
          break;

        case 'R' :
          DisplayCtrlRegs();
          break;

        case 'B' :
          x = cfgbuff[0];
          DisplayBRAM(x);
          break;

        default :
          xil_printf("Bad Command...\n\r");
          break;

        }

        d = 0x00000380 | mode;
        *(pcontrol) = d;
        switch (mode)
        {
          case 2 :
            xil_printf("Running  User Tone Demo\n\r");
            break;

          case 4 :
            xil_printf("Running  User Chirp Demo\n\r");
            break;

          case 6 :
            xil_printf("Running  User FSK Demo\n\r");
            break;

          case 8 :
            xil_printf("Running  User PSK Demo\n\r");
            break;

          case 10 :
            xil_printf("Running  User 4-QPSK Demo\n\r");
            break;

          case 12 :
            xil_printf("Running  User AM Demo\n\r");
            break;

          default :
            xil_printf("Error...\n\r");

        }
      }


char GetUserCmd() {
  long d;
  unsigned int ReceivedCount;
  int i,j;
  char userInput;
  char cmd;
  int cmdend;
//  u32 *ptrCONFIG = &cfgbuff[0];


  CmdValues = 0;
  ReceivedCount = 0;
  userInput = 0;
  cmd = 0;
  cmdend = 0;
  i = 0;
  while(cmdend != 1){
    /* Wait for data on UART */
    while (!XUartPs_IsReceiveData(XPAR_PS7_UART_0_BASEADDR)) {}

    /* Store the first character in the UART receive FIFO and echo it */
    userInput = XUartPs_ReadReg(XPAR_PS7_UART_0_BASEADDR, XUARTPS_FIFO_OFFSET);
    // xil_printf("%c", userInput);

    if (userInput == ';') {
      //for (j=0; j<8; j++){
      //  xil_printf("%x \n\r", cfgbuff[j]);
      //}
      CmdValues = ReceivedCount;
      cmdend = 1;
    }

    // first char has to be a valid command
    else if ((cmd == 0) && (i == 0)) {
       cmd = toupper(userInput);
       //xil_printf("%c\n\r",cmd);
    }

    else if ( (cmd != 0) && (i > 0) && (userInput == ' ')) {
      d = strtoul(datain,NULL,10);
//      d = atoi(datain);
      cfgbuff[ReceivedCount] =  d;
      ReceivedCount += 1;
      i = 0;
      for (j=0; j<sizeof(RecvBuffer); j++){
        RecvBuffer[j] = 0;
      }
    }

    // start parsing space delimited
    else if ((cmd != 0) && (userInput != ' ')) {
      *(datain + i) = userInput;
      i += 1;
    // xil_printf("%c", userInput);
    }
  }
  return cmd;
}

This might be helpful as a general idea. It's a bit rough as it was part of a preliminary experiment to test out some idea. But, the general form is useful.  Note that GetUserCmd()  is blocking execution of the program until the user enters a command via the UART. That is not always what anyone wants.

If you want to get more daring you will be into strings and conversions, and who knows what...

Edited by zygot
Link to post
Share on other sites
  • 0

how hard would it be to print something, and then look for a "y" or "n" from the user?

I would have a small loop that checks to see if there is input available, and exit the loop when there is. Then get the character and see if its a "y" or "n".

int answer;

int wait4answer=1;

while(wait4answer){

    int wait4keyboard=1;

   while(wait4keyboard){

       wait4keyboard = SOME_FUNCTION_TO_CHECK_IF_SERIAL_DATA_AVAILABLE();

   }

  int char = SOME_FUNCTION_TO_GET_SERIAL_CHARACTER();

  if((char=='y') || (char=='n')){

         answer=char;

         wait4answer=0;

  }

}

 

DO_SOMETHING_WITH_ANSWER(answer);

 

I've done something like this on simple microcontroller projects before. 

I just need to know what the SOME_FUNCTION_TO_CHECK_IF_SERIAL_DATA_AVAILABLE() and SOME_FUNCTION_TO_GET_SERIAL_CHARACTER() functions are called, assuming they exist.
 

It doesn't have to present a shell type interface, it doesn't have to support up-arrow to get previous commands, or backspace to edit the current line of text, it doesn't have to do auto-complete when "tab" is hit.

 

Link to post
Share on other sites
  • 0

This is Xilinx standalone OS we're talking about. Even print statements are discouraged.

But the SDK ( I haven't used Vitis ) has a number of example applications for just about any interface attached to your HW system. Just read through the code carefully to avoid nasty surprises, like having to have a hardware loopback connection.

If you say it's easy, that's fine. Call me in an hour and let me know how you did it.

p.s.

What should we think of someone who asks for help, and oh by the way if this is complicated can I have a step by step tutorial, because my time is too important to find the answers for myself. And then, to the first person willing to give up his time to reply gets a 'how hard can it be?' retort? You wanna provide the punchline or should I?

Last thought:

I've done simple menu driven programs for Windows and Linux and even when the std input device is a keyboard trying to detect user input in a non-blocking way isn't straight forward ( on Linux at least ) . But we're talking about a UART. For an embedded ucontroller you can always check uart registers to check for an incoming character.

Edited by zygot
Link to post
Share on other sites
  • 0

"And then, to the first person willing to give up his time to reply gets a 'how hard can it be?' retort?"

You said "you have parse the user input". and later you said "you will be into strings and conversions, and who knows what..."  But that's way more complicated than I am looking for. I don't need to parse anything or deal with creating string classes.  I tried to clarify that its a much more rudimentary problem by asking:

"how hard would it be to print something, and then look for a "y" or "n" from the user?"

There is clearly a misunderstanding going on here, and that was a legitimate attempt to clarify.  


 

"can I have a step by step tutorial, because my time is too important to find the answers for myself. "

You have that exactly backwards. I said "If its complicated, could someone point me to a tutorial somewhere?"  as in, if its complicated, but its covered somewhere already, then your time is too important to bother explaining it to a noob like me, just post the URL and I'll go wade through the answer there.

 

this appears to be a continuation of the whole misunderstanding going on in this thread



 

Link to post
Share on other sites
  • 0

If you are going to spend any significant time using the Xilinx tools, especially the SDK or Vitis, it's worth the effort to learn how to use the GUI interface to dig down into the support libraries and code. While not always up to date or helpful for some issues, there's plenty of assistance and documentation on how to use all of the standalone libraries. If you don't want to use the standalone libraries directly you can write programs just as if were any old micro-controller. The IDE is pretty good at locating source code and getting information on how to use the libraries.

But really? You don't get the ironic humor in your posts?

Link to post
Share on other sites
  • 0

You misread my question, responding in what can only be descibed as toxic. And your invocation of "ironic humor" lands as someone saying "all in good fun!" after being abusive.

I've been working as an engineer for decades. Most of it has been asic work. I am very rusty with fpga's. But i am no fool. And the sooner you get that people arent dumber than you just for asking a question, the better off you'll be.

 

Link to post
Share on other sites
  • 0
57 minutes ago, skinnypanda said:

the sooner you get that people arent dumber than you just for asking a question, the better off you'll be.

Nothing about what I've written implies anything about your intelligence or mine, same for experience, same for skill, etc. etc. Frankly if either of us has been abusive, it's been you. You are the only one slinging personal attacks. But you can relax because you won't be hearing from me in the future. I'm sure that you can figure this out on your own but I do hope that you get another reply to your original question. Believe what you want to but my only intention is to help in the best way that i can. I have no power to stop people from inferring things that aren't implied or explicitly written.

Edited by zygot
Link to post
Share on other sites
  • 0

Zygot:"Frankly if either of us has been abusive, it's been you. You are the only one slinging personal attacks."

Yeah, lets do the instant replay:

"What should we think of someone who asks for help, and oh by the way if this is complicated can I have a step by step tutorial, because my time is too important to find the answers for myself. And then, to the first person willing to give up his time to reply gets a 'how hard can it be?' retort? You wanna provide the punchline or should I?"

There's an implication here that I am lazy, too important to google, and ungrateful enough to give a "retort". Unless the "punchline" was something complimentary? Yeah, no...

That entire paragraph is the first salvo of personal attacks in this thread.  You started this thread towards personal attacks. Not me.

All i've done is ask a question, attempt to clarify that question after you misunderstood it, and then pointed out the above paragraph is when this thread started the personal attacks.

The only time i ever said anything about you personally was when i pointed to your comments that were making personal attacks against me.

Oh, and attacking someone by saying i think "my time is too important" and then pretending i am somehow "inferring things that aren't implied or explicitly written"? That is called gaslighting. You were very clear there,  i think my time is too important, quite explicit, very personal, and when called on it, you pretend none of it happened. Gaslighting is when someone attacks and then tries to rewrite and rearrange history so they are the victim.

So, a personal attack, followed by gaslighting. 

And the only thing i have said on this thread about you is pointing out where you started this thread down the path of personal attacks.

Link to post
Share on other sites
  • 0

Hello,

I'll be honest in saying that I've read through this thread a few times now, but I don't understand how the breakdown in communication happened. I do not think it is my place to decide who is right or wrong or who started what, nor is a random forum thread on the internet the place to do it; we're all adults who know they can learn more things regarding FPGAs/SoC hardware and software tools.

But I'll try to answer some of the original questions.

On 9/2/2021 at 12:23 PM, skinnypanda said:

how hard would it be to print something, and then look for a "y" or "n" from the user?

Not terribly difficult with the existing Xilinx functions, though I had to do some digging to find them.

On 9/2/2021 at 12:23 PM, skinnypanda said:

I just need to know what the SOME_FUNCTION_TO_CHECK_IF_SERIAL_DATA_AVAILABLE() and SOME_FUNCTION_TO_GET_SERIAL_CHARACTER() functions are called, assuming they exist.

These functions are the same ones used in zygot's original reply:

On 9/2/2021 at 12:07 PM, zygot said:

/* Wait for data on UART */
    while (!XUartPs_IsReceiveData(XPAR_PS7_UART_0_BASEADDR)) {}

^This is checking for serial data being available

On 9/2/2021 at 12:07 PM, zygot said:

/* Store the first character in the UART receive FIFO and echo it */
    userInput = XUartPs_ReadReg(XPAR_PS7_UART_0_BASEADDR, XUARTPS_FIFO_OFFSET);

^This one gets gets the actual character and stores it in a user variable.

You can then do a switch case statement like zygot did to process if the user chose 'y' or 'n' or could do a if else if statement style like the one that is available on Xilinx's Github, https://github.com/Xilinx/embeddedsw/blob/master/XilinxProcessorIPLib/drivers/uartps/examples/xuartps_low_echo_example.c (which uses the same XUartPS_ functions from various Xilinx provided libraries) that takes a letter character received in the serial terminal and then spits back out the opposite case (upper or lower) of that same character. You could then modify either example to do some other function once it gets that that particular case/if statement. I can't find the power supply for my zedboard at the moment, but I was able to readily confirm that Xilinx's example worked as is on a blank C application project on a Arty Z7-10 (using Tera Term) that had more or less the exact same block design as created in the tutorial you linked (minus the custom IP) in Vivado/Vitis 2020.1. The caveat with the Xilinx example is that it's a blocking function in the sense that it's doing nothing else while waiting for the user input; maybe that's fine for your system, maybe not.

Thanks,
JColvin

Link to post
Share on other sites
  • 0

" I had to do some digging to find them."

I haven't been able to find anything at all. It's a bit odd how obscure this stuff is sometimes.

 
 "userInput = XUartPs_ReadReg(XPAR_PS7_UART_0_BASEADDR, XUARTPS_FIFO_OFFSET);"

Yeah, that's pretty obscure.

;)

But I was able to get this to work. 

ten lines of code and two very obscure calls, and it's doing what I need.

thanks for the help.

 

 

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now