Gpio doesn't work on HiFive1 rev B [SOLVED]

I have written simple program with crude delay (sleep() doesn’t work and cpu interupt is too complicated for quick testing) to toggle pin high and low to blink led:

#include <stdio.h>

//#include <unistd.h>
#include <time.h>
#include <metal/gpio.h>


void delay(int number_of_seconds) //not actually number of seconds
{

    // Converting time into milli_seconds
    int milli_seconds = 1000 * number_of_seconds;

    // Stroing start time
    clock_t start_time = clock();

    // looping till required time is not acheived
    while (clock() < start_time + milli_seconds);

}



int main (void)
{

	struct metal_gpio *gpio_device;

	gpio_device = metal_gpio_get_device(0);

	//I have tried these in all combinations, but it still doesn't work
	//metal_gpio_toggle_pin(gpio_device, 13); //13 is the pin
	//metal_gpio_disable_input(gpio_device, 13);
	//metal_gpio_enable_output(gpio_device, 13);
	printf("metal_gpio_set_pin \n");

	unsigned int d0 = 0;
	while (1)
	{
		metal_gpio_set_pin(gpio_device, 14, 1); //this line does absalutely nothing
		//sleep (1000);
		delay(10000); //10000 = 1 second
		metal_gpio_set_pin(gpio_device, 14, 0); //this line does absalutely nothing
		delay(10000);
		++d0;
		printf("debug: %u \n", d0);
	}

	//metal_gpio_set_pin(gpio_device, 15, 200); //pin device, pin, state

    return 0;
}

I am experiencing very weird behavior. 15. and 16. pins are permamently on, 14. pin is permamently off. 13. pin flashes 2 or 3 times fast at program start. I have no slightest clue, what I am doing wrong since there are exacly 0 sample programs for manipulating pins. There is absalute shortage of sample programs. Keep in mind, that I have spent hours trying different combinations and none of them work. I looked in Metal documentation about gpio (https://sifive.github.io/freedom-metal-docs/apiref/gpio.html).

I am using Ubuntu 19.04 and latest Freedom Studio (Version: 4.7.2.2019-03-4). I have HiFive1 Rev B board.

What I am doing wrong?

Edit: I was using the incorect pins. I should have used gpio pins (last page contains layout - https://sifive.cdn.prismic.io/sifive%2F8d7b8385-64e3-4914-8608-8568412c8aae_hifive1b-getting-started-guide.pdf)

I performed a test and there are list of pins that work: 2, 3, 4, 5, 6, 7, 9, 10, 16, 17, 18, 19
I hope, that someone finds this helpful. BTW gpio pins 19, 21, 22 are responsible for RGB led, but behaviour is weird, if you use more than 1 color at the time.

Hey!
Be aware that the pin number is not equivalent to the gpio number.
You can find a diagram on the last page of the Getting Started Guide.
I get it working changing these lines of your code:

...
metal_gpio_enable_output(gpio_device, 16);
...
metal_gpio_set_pin(gpio_device, 16, 1);
...
metal_gpio_set_pin(gpio_device, 16, 0); 
...

I’m able to get a flashing led on pin 2 which corresponds to gpio 16.

Still I also see strange results when trying this for pin 13 (gpio 5). The same with some other pins.
I think it might be that there are io_function active on these pins like PWM, UART and so on.
I didn’t have time yet to test all pins and figure out how to disable the io_function, but I’ll try to later.

edit:
Indeed it was the io_functions leading to strange behavior of some gpios.
I couldn’t find a metal function to do this, but I managed to disable them with the following asm:

#define GPIOBASE	0x10012000
#define GPIO_IOF_EN     0x38
li t0, GPIOBASE
sw zero, GPIO_IOF_EN(t0)

still not under my control is pin 12 for whatever reason

2 Likes

hello i have the issue.
I cant get an LED blinking connected o pin 2.
also random pins on my board(hifi 1 rev b) are always HIGH.
can you please help

Are you talking about GPIO pin 2 (physical pin 10) or physical pin 2 (GPIO pin 18)?

I’ve just tested with some rust code and everything works for me for both pins. You need to make sure the pin is asserted into output mode only. If you want I can gist the code but as I said it’s in rust.

physical pin 2 GPIO pin 18.

can you please share the test code with me. It’ll be of great help

Here’s the code

It uses the hifive1 crate and others from the rust embedded-hal side.

Video of working LED

NOTE: the pin!(gpio, dig2) macro just translates to gpio.pin18

Also forgot to mention I’m using latest greatest with updates from @Disasm meaning if you want to get this to work using current crate versions you will need to use the older e310x-hal approach using Peripherals struct instead of the DeviceResources. Those aren’t published yet. Or you can check out the latest master branches and use a workspace :smiley:

1 Like

Thank You
I will look into it.

Hi,

I had some issues getting an I/O pin working as well. I was trying to turn on and off a pin to control an LED to test. It was not as intuitive as I thought it would be and I came across this post a few times. If anyone is interested, here’s what I have using Freedom Studio and E SDK. I’m pretty new to this framework so the comments may not make sense. Also, some of the methods may not be the most efficient but I at least got it working. :stuck_out_tongue_winking_eye:

Here’s the gist of it:

/******************************************************************************
    sifive_Hifive1blink.c
    
    DEVELOPMENT ENVIRONMENT SPECIFICS:
      Firmware developed using Freedom Studio v4.12.0.2019-08-2
      on Windows 10

    ========== RESOURCES==========
    Freedom E SDK
    
    ========== DESCRIPTION==========
    Using the built-in LED. To test with different pin,
    simply modify the reference pin and connect a standard LED  
    and 100?O resistor between the respective pin and GND.
    
    LICENSE: This code is released under the MIT License (http://opensource.org/licenses/MIT)
  ******************************************************************************/

#include <stdio.h>      //include Serial Library
#include <time.h>       //include Time library (might not need)?
#include <metal/gpio.h> //include GPIO library, https://sifive.github.io/freedom-metal-docs/apiref/gpio.html

//#define builtin_LED 5 //IC's GPIO = 5, pin silkscreen = 13, this line won't work, we need an integer...

//custom write delay function since we do not have one like an Arduino
void delay(int number_of_microseconds) //not actually number of seconds
{

  // Converting time into multiples of a hundred nS
  int hundred_ns = 10 * number_of_microseconds;
  
  // Storing start time
  clock_t start_time = clock();
  
  // looping till required time is not achieved
  while (clock() < start_time + hundred_ns);
  
}//end delay



int main (void) {
  //make instance of GPIO
  struct metal_gpio *led0;

  //Note: The sequence of these commands matter!

  //Get gpio device handle, i.e.) define IC pin here where IC's GPIO = 5, pin silkscreen = 13
  //this is the GPIO device index that is referenced from 0, make sure to check the schematic
  led0 = metal_gpio_get_device(0);

  // quick check to see if we set the metal_gpio up correctly, this was based on the "sifive-welcome.c" example code
  if (led0 == NULL) {
    printf("LED is null.\n");
    return 1;
  }
  //Pins are set when initialized so we must disable it when we use it as an input/output
  metal_gpio_disable_input(led0, 5);

  //Set as gpio as output
  metal_gpio_enable_output(led0, 5);

  //Pins have more than one function, make sure we disconnect anything connected...
  metal_gpio_disable_pinmux(led0, 5);

  //Turn ON pin
  metal_gpio_set_pin(led0, 5, 1);



  while (1) {//loop through, sort of like an Arduino loop()

    //Turn OFF pin
    metal_gpio_set_pin(led0, 5, 0);
    //Use custom "delay" function
    delay(2000000); //2000000 "micro-seconds" ~ 1 second, through experimentation... 
    //Turn ON pin
    metal_gpio_set_pin(led0, 5, 1);
    //Use custom "delay" function
    delay(2000000);

    /***************************************************

    //crude method of "delaying" without messing with the cpu's interrupts...
    for (int i = 0; i < 25000; i++) {
      metal_gpio_set_pin(led0, 5, 0);
    }
    for (int i = 0; i < 25000; i++) {
      metal_gpio_set_pin(led0, 5, 1);
    }

    ***************************************************/
  }

  // return
  return 0;
}//end main