Question

Hello everyone,

I bought for my Zedboard the GPS Pmod.

I wrote something about reading the datas out with UART.

Do you have some example code, how to do this? And is it possible to connect the GPS Module directly to my Pmod connections? And do I take the AXI GPIO block in the block diagram to solve this?

 

Edit:

I was able to solve it. But I do not really know now why. I think that I did some mistakes with the interrupt handling. I use now polled mode and now it is working perfectly. But I am still interested in the hardware design. I want to understand how the interrupt is working

Edited by HelplessGuy

Share this post


Link to post
Share on other sites

Recommended Posts

  • 0

Hi @HelplessGuy,

Please attach the code you are using to access the other functions listed below:

double GPS_getTime(PmodGPS *InstancePtr);

int GPS_getNumSats(PmodGPS *InstancePtr);

double GPS_getPDOP(PmodGPS *InstancePtr);

double GPS_getAltitude(PmodGPS *InstancePtr);

double GPS_getSpeedKnots(PmodGPS *InstancePtr);

double GPS_getSpeedKM(PmodGPS *InstancePtr);

double GPS_getHeading(PmodGPS *InstancePtr);

thank you,

Jon

Share this post


Link to post
Share on other sites
  • 0

Hi  @D@n Hi @jpeyron

I am using the following code:

#include <stdio.h>
#include "xparameters.h"
#include "sleep.h"
#include "XGpio.h"
#include "PmodGPS.h"
#include "XUartLite.h"

#define		PERIPHERAL_CLK	100000000 	//Clock definition for GPS
#define		BASEADDRESS_GPS	0x2000000	//from 0x2000000 to 0x3FFFFFF memory for received GPS data
#define		BASEADDRESS_TEST	0x4000000	//from 0x4000000 to 0x5FFFFFF memory for received GSM data

PmodGPS 	GPSInst;
XUartLite	UARTInst;
XGpio		GPIOInst;

uint gpssize = 0;
char GPS_data[] = "<GPS did not get a ping>";

char* ptr_gps = (char*)(BASEADDRESS_GPS);
double* ptr_test = (double*)(BASEADDRESS_TEST);

void init(void);
void Receive_GPS_Data(void);

int main (void)
{
	init();
	Receive_GPS_Data();
}

void init(void)
{
	/*
	 * Initialize GPS
	 */
	GPS_begin(&GPSInst, XPAR_PMODGPS_0_AXI_LITE_GPIO_BASEADDR, XPAR_PMODGPS_0_AXI_LITE_UART_BASEADDR, PERIPHERAL_CLK);
	GPS_setUpdateRate(&GPSInst, 1000);
}

void Receive_GPS_Data(void)
{
	GPS_bool status;

	status = GPS_getSentence(&GPSInst, ptr_gps);
	if (status == 0)
	{
		printf("No Data received!\n");
		//return;
	}
	printf("get Sentence: %s\n", *ptr_gps); //debug

	*ptr_test = GPS_getTime(&GPSInst);
	printf("Satelite Time: %f\n", *ptr_test); //debug
	printf("\n");
}

The return I get is the flowing:

image.thumb.png.27d7d2145dca015c7e810f17024edb72.png

  • So I receive data (you can see it that I do not enter the if) the problem is only, that there is no time. And that the char is looking strange!

Hope for some help, greetings!

Edited by HelplessGuy

Share this post


Link to post
Share on other sites
  • 0

@HelplessGuy

Looks like you never set the baud rate.  The GPS NMEA channel runs at a 9600 baud, 8-data bits, no -parity, one stop bit mode.  If you get any of this wrong, the incoming data will be garbled, just like the sentence result you shared above.

Dan

Share this post


Link to post
Share on other sites
  • 0

Hi @HelplessGuy,

It looks like you are printing the pointer address instead of whats at the pointer. Please change the following line:

printf("get Sentence: %s\n", *ptr_gps); //debug

to 

printf("get Sentence: %s\n", ptr_gps); //debug

thank you,

Jon

Share this post


Link to post
Share on other sites
  • 0

Hi @jpeyron I have tested it without the *. This is not changing anything. Only thing that is happening, that I get a warning that the expected format is char* and not char. The hint of  @D@nseems more correct.

How is the way to implement this? I do not find any function for this in the PmodGPS.h file

 

Share this post


Link to post
Share on other sites
  • 0

@HelplessGuy

@jpeyron had pointed out a valid bug, one I'm sorry I missed.  If you define something as a char *, and then pass it to a printf("%s,..._); you'll want to pass the name without the *. That should leave you wondering about whatever other bugs you may have in your code.  It looks like you have a similar bug on two lines with ptr_test as well.  There should be no "*" in ptr_test =GPS_getting...., nor in the printf that follows. 

Share this post


Link to post
Share on other sites
  • 0

Hi @D@n @jpeyronI tested the same with creating a variable char test (without any pointers). I had the same problems. So I think, that there are some mistakes in the functions. Do you have any experiences about that, or working sdk code for reading the satelite time and using the latetude and longitude function

Share this post


Link to post
Share on other sites
  • 0

@HelplessGuy,

It looks like you are struggling with a basic misunderstanding of how C works.  You might wish to check some blogs or tutorials to learn a bit more about C pointers.  In particular, if you declare ptr_gps as a character, then it will only ever represent one character--not what you want.  A string in C is represented by a character array.  For this you *need* a pointer.  Declaring it as anything else won't work.

The misunderstanding seems to come in from the fact that your print statement needs to pass the pointer, not the character value referenced by the pointer.  To do this you want to pass ptr_gps without the star in front of it.  Keep your declaration the same.

Since this is a confusion about how C works, let's build an example that you can try on your desktop first.  Once you understand this working on your desktop, then you'll have the confidence to proceed to MicroBlaze again.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
  
char *get_string(char *ptr) {
	strcpy(ptr, "This is a string\n");
	return ptr;
}

char	*sptr;

int main(int argv, char **argv) {
  // Allocate a space to hold our string
  sptr = malloc(128);
  
  // Get a copy of our string
  sptr = get_string(sptr);
  
  // Print the string out.  Note the lack of the *
  printf("My string is: %s\n", sptr);
  
  // Free the space we allocated for our string in the first place
  free(sptr);
  
  // And exit with success
  return EXIT_SUCCESS;
}

I've just scribbled this together.  I haven't tested this, so it may or may not have bugs within it.

You might want to take particular note of what lines contain the "*" and which lines don't.  It's important.  In particular, the variable declarations for the pointers use the *, but nowhere else.  Were this code to reference a value found within the string, we might've referenced either *sptr or sptr[0], but that's not what you were trying to do above and so I haven't done that here.  Further, to print the whole string, you need to keep the "*" out of the printf.  Had you wanted to print one character only, that would have a different syntax.

A good C/C++ tutorial should also explain this in case I'm confusing you.

Dan

Share this post


Link to post
Share on other sites
  • 0

Hi @D@n  @jpeyron 

thanks for this. But I do not think, that the pointers are the problem at the moment. I think, that there is a mistake in the function.

double test;
test = GPS_GetTime(&GPSInst);

printf("%f\n", test);

I tested it also with this. And I also get the value 0.000 back. So we should forget the pointers at the moment and focus, why this function is not delivering any correct value.

Share this post


Link to post
Share on other sites
  • 0

@HelplessGuy,

This point is actually going in the wrong direction and taking you away from finding whatever bug you are struggling with.  Your first question should be whether or not you are receiving valid GPS data, and only secondly whether or not that data is processed properly.

GPS data is provided via a stream of text from the PMod GPS's UART port.  It's pseudo-human legible.  At this point, you need to first demonstrate that you are able to  receive the stream of text.  Only after that does it make sense to talk about whether the text can be decoded properly.  This sends us back to the issue with the character pointers that we were discussing above.

Have you tried a simple design that just connects the serial output port to a serial input port of your zedboard?  (I assume it has one in MDIO somewhere, although I haven't used the Zedboard enough to know.)  You would then need to process, by hand, enough of the NMEA messages to know that a signal exists, that it has been properly received, and that the GPS receiver had actually gotten a fix.  IMHO, this is the step you are missing.

Dan

Share this post


Link to post
Share on other sites
  • 0

Hi @D@n for me it seems, that the given functions from digilents pmodgps.h heather are doing already the right stuff that I only have to print the data out. There is a GPS.ping existing for doing the IMHO, but it also seems as if it is not working. greetings,

Share this post


Link to post
Share on other sites
  • 0

@HelplessGuy,

The fundamental discipline of all engineering is to be able to take a problem, such as the GPS not working for you, and to break it down into pieces in order to figure out which piece is broken.  This was my advice to you above.

I'm a little confused by your response saying that you don't need to do this.  Does that mean that things are finally working for you?

Dan

Share this post


Link to post
Share on other sites
  • 0

I must say I share D@n's opinion here.

What I would do is

  • start with a plain serial port. Create a dumb (non-clocked) FPGA design that routes the FTDI chip's UART pins to some GPIOs, and hook up the GPS module. Alternatively, use a standalone FTDI-to-UART module or equivalent.
  • Fire up teraterm (e.g.) on the PC, open the COM port, set the correct baud rate.
  • Check that the GPS module responds as expected.
  • Check that the message format is exactly as you expect it.

I suspect this assumption

>> it seems, that the given functions from digilents pmodgps.h heather are doing already the right stuff

won't hold.

What you're trying reminds me of the old joke about a gynecologist retraining as a car mechanic🙂

Share this post


Link to post
Share on other sites
  • 0

Hi @HelplessGuy,

this piece of code demonstrate how to perform UART I/O communications with your board. It test the switches , buttons , and LEDs status using Teraterm.

/* Engineer : Jordan Christman @ Udemy
 *
 *
 * This file is a generated sample test application.
 *
 * This application is intended to test and/or illustrate some
 * functionality of your system.  The contents of this file may
 * vary depending on the IP in your system and may use existing
 * IP driver functions.  These drivers will be generated in your
 * SDK application project when you run the "Generate Libraries" menu item.
 *
 */

#include <stdio.h>
#include <string.h>
#include "xparameters.h"
#include "xil_cache.h"
#include "xiomodule.h"

int main()
{
   int done = 0;
   int byte_count = 0;
   int execute_cmd;
   char command[6];
   char led_cmd[3];
   char led_num[2];
   u8 tmp_rx_buf;
   u8 rx_buf[40];
   u32 button_data = 0;
   u32 switch_data = 0;
   u32 led_data = 0;
   u32 data;
   XIOModule iomodule;

   Xil_ICacheEnable();
   Xil_DCacheEnable();

   // Initialize module
   data = XIOModule_Initialize(&iomodule, XPAR_IOMODULE_0_DEVICE_ID);
   data = XIOModule_Start(&iomodule);
   data = XIOModule_CfgInitialize(&iomodule, NULL, 1);
   xil_printf("CFInitialize returned (0 = success) %d\n\r", data);

   print("---Enter a command---\n\r");

   // While loop until user enters "finish" command
   while(done == 0)
   {
	   execute_cmd = 0;
	   memset(rx_buf, 0, sizeof(rx_buf));
	   byte_count = 0;

	   // Build up message from UART Terminal
	   while (execute_cmd == 0)
	   {
		   // Read UART data
		   while ((data = XIOModule_Recv(&iomodule, &tmp_rx_buf, 1)) == 0);

		   rx_buf[byte_count] = tmp_rx_buf;

		   if (rx_buf[byte_count] == '\n')
			   execute_cmd = 1;

		   byte_count++;
	   }

	   // Build the command arrays
	   memcpy(command, &rx_buf[0], 6);
	   memcpy(led_cmd, &rx_buf[0], 3);
	   memcpy(led_num, &rx_buf[4], 2);

	   // Read the button & switch status
	   button_data = XIOModule_DiscreteRead(&iomodule, 1);
	   switch_data = XIOModule_DiscreteRead(&iomodule, 2);

	   // Execute the received command
	   if (strcmp(led_cmd, "led") == 0)
	   {
		   led_data = led_num[1] - 48;

		   if ((led_num[0] - 48) == 1)
			   led_data += 10;

		   XIOModule_DiscreteWrite(&iomodule, 1, led_data);
	   }
	   else if (strcmp(command, "button") == 0)
		   xil_printf("Button Status: %d\n\r", button_data);
	   else if (strcmp(command, "switch") == 0)
		   xil_printf("Switch Status: %d\n\r", switch_data);
	   else if (strcmp(command, "finish") == 0)
		   done = 1;
	   else
		   print("Command is invalid, re-enter below:\n\r");

// Debugging print outs below
//	   print("Command: ");
//	   print(command);
//	   print("\n\r");
//
//	   print("LED_cmd: ");
//	   print(led_cmd);
//	   print("\n\r");
//
//	   print("LED_num: ");
//	   print(led_num);
//	   print("\n\r");

   }

   print("---Exiting main---\n\r");
   Xil_DCacheDisable();
   Xil_ICacheDisable();
   return 0;
}

hope will benefit from it.

Share this post


Link to post
Share on other sites
  • 0

Hi @HelplessGuy,

I was able to GPS_getTime() and GPS_getNumSats() to send data through tera term as shown in the screen shot attached below. xil_printf does not support printing doubles as discussed in this xilinx forum thread here. I have also attached my main.c SDK file. 

cheers,

Jon

GPS_TIME_NumStat.jpg

main.c

Share this post


Link to post
Share on other sites
  • 0

Hi @HelplessGuy,

Here is the complete Vivado 2018.2 Nexys 4DDR with Pmod GPS project I used.  I currently do not have the bandwidth to make the same project for the Zedboard. I would suggest to open this project and look at how I connected the Pmod GPS.

1) For the Zedboard all you would need to do is add the zynq processor(make sure to use the digilent board files when creating the project). Then at the vivado library to the ip repository. Then add the Pmod GPS to one of the ports I.E. JA,Jb,JC.

2) Next run block automation on the zynq processor and add interrupts to it. Then connect the interrupt to the interrupt on the Pmod GPS. Next validate the block design create a wrapper and generate the bitstream.

3) Then export hardware including the bitstream and launch SDK.

4) Once in SDK create an empty application. Add the main.c to the scr file in the application.  Program FPGA and rich click on the application and run as->launch on hardware(system debugger). 

cheers,

Jon

Share this post


Link to post
Share on other sites
  • 0

Hi @HelplessGuy,

Please try making a project with only the Pmod GPS and Zynq processor. Then add the UART and GPIO IP cores after you have got the Pmod GPS going correctly. Also you have changed the Zynq processor. For your initial project with just using the Pmod GPS only add the interrupts to the  ZYNQ processor and leave everything else with the default settings.  Please use the Digilent board files which not only works with the Digilent IP Cores like the Pmod GPS IP Core but also becomes the default setting for the ZYNQ processor when running block automation. 

thank you,

Jon

Share this post


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