0
\$\begingroup\$

My experience with writing embedded C is pretty limited so there will probably be a simple solution to this question.

I am using a Microblaze softcore on a basys 3 FPGA development board and will have a state machine that will print the user some options from a main menu, and prompt the user to press some keys which will then advance the state machine to the correct place. However my question, is how should I compare to check which key the user has actually pressed?

I had firstly read the UART receive buffer using the built-in Xilinx functions which allowed me to see which characters were pressed, but then I realised I could maybe simplify this using the gets() C function. I have tried making the text 1 character long and comparing it with another character or string value in an if statement, but it never seems to evaluate to true (I have LEDs on the board connected to the outputs of the Microblaze so a specific character is pressed, I just set some LED pattern. Here the LED never comes on. Any advice?

EDIT

I have a feeling this if statement never evaluates true because I think I am comparing the address in memory where text is stored, and not the value of text possibly?

Here is the C code below:

#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#include "xgpio.h"
#include "xuartlite.h"

#define GPIO_EXAMPLE_DEVICE_ID  XPAR_GPIO_0_DEVICE_ID

#define UARTLITE_DEVICE_ID      XPAR_UARTLITE_0_DEVICE_ID

#define DATA 0b10101010

u8 RecvBuffer[1];   /* Buffer for Receiving Data */

int UartLiteSelfTestExample(u16 DeviceId);

XGpio Gpio; /* The Instance of the GPIO Driver */

XUartLite UartLite;      /* Instance of the UartLite device */

int main()
{

    init_platform();

    int UART_Status;
    int GPIO_Status;

    UART_Status = UartLiteSelfTestExample(UARTLITE_DEVICE_ID);
    if (UART_Status != XST_SUCCESS) {
        xil_printf("Uartlite Setup Failed!\r\n");
    }
    else{
        xil_printf("Uartlite Setup Successful!\r\n");
        xil_printf("\n");
    }

    /* Initialise the GPIO driver */
    GPIO_Status = XGpio_Initialize(&Gpio, GPIO_EXAMPLE_DEVICE_ID);
    if (GPIO_Status != XST_SUCCESS) {
        xil_printf("GPIO Initialisation Failed!\r\n");
        xil_printf("\n");
    }
    else {
        xil_printf("GPIO Initialisation Successful!\r\n");
        xil_printf("\n");
    }

    /* Set the direction for all signals as outputs */
    XGpio_SetDataDirection(&Gpio, 1, 0x00);

    xil_printf("--------------------------------\n\r");
    xil_printf("           Main Menu\n\r");
    xil_printf("--------------------------------\n\r");
    xil_printf("\n");
    xil_printf("Options: 1 - Setup\r");
    xil_printf("         2 - Peek\r");
    xil_printf("         3 - Status\r");
    xil_printf("         4 - Run\r");
    xil_printf("\n");

    //MY QUESTION IS INSIDE THIS WHILE LOOP!

    while(1){

        char text[1];
        gets(text);
        xil_printf("%s", text);

        if (text == "1"){
            XGpio_DiscreteWrite(&Gpio, 1, 1);
        }
        }

    cleanup_platform();
    return 0;
}



/// function body ///

int UartLiteSelfTestExample(u16 DeviceId)
{
    int Status;

    /*
     * Initialise the UartLite driver so that it is ready to use.
     */
    Status = XUartLite_Initialize(&UartLite, DeviceId);
    if (Status != XST_SUCCESS) {
        return XST_FAILURE;
    }

    /*
     * Perform a self-test to ensure that the hardware was built correctly.
     */
    Status = XUartLite_SelfTest(&UartLite);
    if (Status != XST_SUCCESS) {
        return XST_FAILURE;
    }

    return XST_SUCCESS;
}

```
\$\endgroup\$
2
  • 2
    \$\begingroup\$ Please note that the gets function has been flagged as problematic for a very long time, which has mainly to do with potential for buffer overruns on a hosted system. But it's also a similar problem on embedded systems, in case you receive different UART input than you expected, for whatever reason. Consequently gets was flagged as obsolescent back in the 1990s and finally permanently removed from the C language in year 2011. Therefore, if your compiler allowed you use it still, your compiler is outdated and non-conforming. You might want to look into that. \$\endgroup\$ Commented Aug 11, 2023 at 10:51
  • 1
    \$\begingroup\$ @Lundin Oh that is interesting. The compiler I am using does allow gets() although I am now using fgets() instead. I must take a look and see which compiler I am using. Thanks for pointing that out. \$\endgroup\$ Commented Aug 11, 2023 at 17:17

1 Answer 1

1
\$\begingroup\$
char text[1];
gets(text);

It seems you only want to read a single character, instead of a string of characters. Then you should rather use getchar.

xil_printf("%s", text);

To print a single character, you should use xil_printf("%c", text[0]).

"%s" expects a zero-terminated string, which you don't provide.

if (text == "1")

To compare c-strings, you should use strcmp instead of ==. But in your case, you only want to compare a single character, so use if (text[0] == '1') instead.


But I do want the user to enter strings instead of characters, I had one character just to try and get something to work.

Then you need to specify a buffer with the maximum expected length.

For example: char text[256];


When I try to use strcmp() on the microblaze, I get an error running out of the 64kB of local memory.

I can't imagine that in this instance strcmp is the problem. Usually it's implemented very efficiently. I rather expect that the strings aren't zero-terminated, and therefore it keeps on comparing until the memory space is violated.

Make sure that the string buffer is filled with zeroes:

memset(text, 0, sizeof(text));


Can this be done without strcmp() or maybe there is a built-in Xilinx function that is more memory friendly?

Sure. strcmp is quite a simple function.

StackOverflow has some custom implementations: Implementation of strcmp


I still don't understand my mistake when comparing strings. I have two arrays both 20 characters long, one for the user input read by gets() and a second one that I define as "hello". If I type hello into the serial terminal and read with gets(), strcmp() returns non-equal. Why is this?

"hello" is essentially an array containing following chars: 'h', 'e', 'l', 'l', 'o', '\0'

I'm assuming you've zeroed text[20], so the zero-terminator shouldn't be the issue.

My next guess is that you're not only sending the characters h, e, l, l, o, but also a carriage return character (\r), line feed (\n), or both.

To test this, try the following:

if (strncmp(text, "hello", strlen("hello")) == 0)
{
    // `text` starts with the string "hello" 
}

strncmp is similar to strcmp, but a maximum string length is provided.

strlen("hello") returns the number of characters of the string "hello" without the zero-terminator.

So strncmp(text, "hello", strlen("hello")) only compares the initial 5 characters, and would ignore any additional characters like \r or \n.

\$\endgroup\$
5
  • \$\begingroup\$ Thank you, this works now. But I do want the user to enter strings instead of characters, I had one character just to try and get something to work. When I try to use strcmp() on the microblaze, I get an error running out of the 64kB of local memory. Can this be done without strcmp() or maybe there is a built-in Xilinx function that is more memory friendly? \$\endgroup\$ Commented Aug 8, 2023 at 10:51
  • 1
    \$\begingroup\$ I've edited my post. \$\endgroup\$ Commented Aug 8, 2023 at 12:04
  • \$\begingroup\$ Thanks, I forgot to include the string.h header file, I can now use strcmp(). I still don't understand my mistake when comparing strings. I have two arrays both 20 characters long, one for the user input read by gets() and a second one that I define as "hello". If I type hello into the serial terminal and read with gets(), strcmp() returns non-equal. Why is this? \$\endgroup\$ Commented Aug 8, 2023 at 12:33
  • 1
    \$\begingroup\$ @David777 It isn't custom to send strings over UART with a terminating zero at the end. More likely strings end at carriage return (\r dec 13) or line feed (\n dec 10). You will have to convert these into C strings upon reception by appending a zero terminator manually, or otherwise you cannot pass them to the C string handling functions. \$\endgroup\$ Commented Aug 11, 2023 at 10:56
  • \$\begingroup\$ @Lundin Yeah you are correct. Thanks! I just figured this out and now it all works well. \$\endgroup\$ Commented Aug 11, 2023 at 17:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.