FE310 Hello World, general GPIO, The missing manual?

This should be easy, but I must have missed something. I’m using a LoFive dev board and trying to get started by flashing an LED. Actually that’s one step ahead of where I am, I’m trying to drive a pin, GPIO5 of the device, High. That might be something as minimal as:

#define OUTPUT_ENABLE 0x08
#define OUTPUT_PORT   0x0C

#define GPIO_BASE     0x10012000

uint32_t *output_enable = (uint32_t *)GPIO_BASE + OUTPUT_ENABLE;
uint32_t *output_port   = (uint32_t *)GPIO_BASE + OUTPUT_PORT;

*output_enable = 0x01 << 5;
*output_port   = 0x01 << 5;

while(1);

But it’s not. All I have is the GPIO section of the Manual but that’s not going into too much depth. For example when a pin is configured as an Output pin it has a configurable drive strength, but all the manual has is:

17.5    Drive Strength
When configured as output, each pin has a SW-controllable Drive Strength.

Perhaps the Pin’s Hardware Function is enabled by default? I’ll try mess with that register…
I’ll try to set the Drive Strength of the pin…

Nagh I’m only guessing here. Is there a parent manual which I’m missing for the whole RISC-V arch which has all the options, which that FE310 manual inherits from? Thanks for any help and apologies if I’ve missed something.

The SDK provides some macros to make this easier.

To set the GPIO_5 as an output and drive it high:
GPIO_REG(GPIO_INPUT_EN) &= ~(0x1<< 5) ;
GPIO_REG(GPIO_OUTPUT_EN) |= (0x1<< 5) ;
GPIO_REG(GPIO_OUTPUT_VAL) |= (0x1 << 5) ;

On the LoFive you should see 3.3V on pin 14 after running this.

1 Like

What you are looking for is contained in the FE310 Datasheet. See Table 4.2 - each bit of the DS register corresponds to a GPIO pin, 0 = 1mA and 1 = 20mA drive strength. That is drive strength. How to set the output pin high or low is answered by the previous post.

1 Like

Thank you all!!! Sorry I assume the Datasheet would only be the electronic characteristics and requirements. I’ll grab that and go through it.

Unfortunately I’m away for the weekend and without the where with all to have a go. However thanks a million for answering all my questions. It’s a really interesting development I’d love to be able to buy processors to put into a design but I guess we’re not quite there yet in terms of availability in ones or two for odd projects.

Perhaps the answer to that is FPGA implementation. Which is on my list of things to do but I’m looking at a board which is unavailable till the end of Feb.

Once again thanks a million for all your help.

I’ve finally gotten back to this and at present just going through the basics getting familiar with the toolchain and environment. I’ve not found the NOP function in C or inlined the NOP assembly instruction but I’ve got a question about timings. Or a curious result from timings which is down to something I’m doing wrong with the toolchain. I’ll grant you that my source code ain’t the most elegant but it’s legal.

I’m trying to pulse the GPIO5 pin. At present just with a scope on it, so I’ve not gotten into drive strength. I’ve done a simple loop for a delay counting up to a target value in a for loop. If the loop’s limit is 0x40000000 then the result is an 8.2MHz “square” wave (period of 122nS). So if I double the loop’s limit to 0x80000000 I’d expect to get a period of 244nS and half the frequency down to about 4MHz. Instead the period has done out to 33.2 Seconds. That’s a bit of a jump and I’m not sure why. Compiler optimisation or something?

I’ll include the code here but it’s not much, I could upload scope traces but it’s not going to add anything. I’d be very curious as to why I’m getting that result. Obviously for timers of real duration I’d be looking at Hardware timers and I’ll have a look at that next but in the mean time this is curious.

#include <stdint.h>
#include “platform.h”

#define DELAY for(delay = 0; delay < 0x40000000; delay++);

int main()
{
uint32_t delay;
GPIO_REG(GPIO_INPUT_EN) &= ~(0x1<< 5) ;
GPIO_REG(GPIO_OUTPUT_EN) |= (0x1<< 5) ;
GPIO_REG(GPIO_OUTPUT_VAL) |= (0x1 << 5) ;

  while(1) {
	  DELAY
	  GPIO_REG(GPIO_OUTPUT_VAL) = 0x00 ;
	  DELAY
	  GPIO_REG(GPIO_OUTPUT_VAL) |= (0x1 << 5) ;
  }
  return 0;

}

I’d take a look at what ASM gets generated for each case. You can take a look using the make dasm target (assuming you’re using Freedom E SDK directly) or the Disassembly view if you’re using Freedom Studio.

1 Like

Thank you, I should have thought of that :frowning: Not looked at the assembly as yet. Thanks again for your help

Right I’ve had a look at the assembly and I’m thinking that this might actually be a compiler error. Having said that I’m still getting a feel for this, and my assumptions might be wrong. I’m creating a simple 32 bit unsigned integer as an loop counter. The unsigned specification is the important piece. If the loop termination is 0x40000000 then the compiler generates three lines of assembly:

sext.w	a4,a5
li	a5,1073741824
bltu	a4,a5,.L3

The only difference between the assembly when the loop termination is 0x80000000 is that those three lines are replaced with the single line:

bgez	a5,.L3

That feels wrong since in the first three lines the value 1073741824 is the loop termination value 0x40000000 whereas in the second version of the assembly the termination value 0x80000000 never appears. I’m guessing that the compiler is treating the 0x80000000 as a negative number as the MSB is 1? Then it just does a branch greater then zero? But that variable is unsigned?

I guess I’ll be trying this with a termination of 0x7fffffff when I get a chance. I hope I’ve not made a stupid assumption in this, but I’d expect a variable uint32_t delay = 0x80000000; to be interpreted differently by the compiler.

Oops another thing which I should have done was declared by delaying loop counter as a volatile to stop the compiler optimizing the loop away. That single word change made a lot of difference to the outcome.

1 Like