Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Which bit type declarations should be used? #208

Closed
martinmarcos opened this issue Jul 10, 2017 · 3 comments
Closed

Which bit type declarations should be used? #208

martinmarcos opened this issue Jul 10, 2017 · 3 comments

Comments

@martinmarcos
Copy link

Hello, we are trying to port part of the Ada_Drivers_Library to EDU-CIAA-NXP board (For more information about board you can view to issues 16 and 17 from the embedded-runtimes repository). We started out with the GPIO drivers. We analyzed driver and device code and arrived at the conclusion that it would be necessary to manually modify the ada binding files that were created by svd2ada. The vendor's svd file is messy and it's very difficult to adapt driver and device code to the hardware structures created by svd2ada from this file.

Now, looking at the ada binding files we created from the svd file with svd2ada and comparing them to the binding files for the stm32f429 in both the bsp directory from the embedded-runtimes repository and the svd directory from the Ada_Drivers_Library repository we noticed:

  • That the binding files we created all use the bit types declared in the Interfaces.LPC4337 package as can be observed here.
  • The binding files for the stm32f429_disco bsp in the embedded-runtimes repository all use the bit types declared in the Interfaces.Bit_Types package as can be observed here.
  • The binding files for the stm32f429 in the Ada_Drivers_Library all use the bit types declared in the HAL package as can be observed here.

So our question is which one should we use in each case and why?

Regards.

@Fabien-Chouteau
Copy link
Member

Hello Martin,

We analyzed driver and device code and arrived at the conclusion that it would be necessary to manually modify the ada binding files that were created by svd2ada.

I prefer that you fix the vendor SVD files and check them in the svd2ada repo. The idea is to keep the process 100% automated so that if we improve code generation, we can regenerate the files without any manual action. Patch the sources not the binary :)

The vendor's svd file is messy and it's very difficult to adapt driver and device code to the hardware structures created by svd2ada from this file.

Can you elaborate on this? I had a look at the generated code, it looks similar to what we have with the STM32s.

Now, looking at the ada binding files we created from the svd file with svd2ada and comparing them to the binding files for the stm32f429 in both the bsp directory from the embedded-runtimes repository and the svd directory from the Ada_Drivers_Library repository we noticed:

That the binding files we created all use the bit types declared in the Interfaces.LPC4337 package as can be observed here.
The binding files for the stm32f429_disco bsp in the embedded-runtimes repository all use the bit types declared in the Interfaces.Bit_Types package as can be observed here.
The binding files for the stm32f429 in the Ada_Drivers_Library all use the bit types declared in the HAL package as can be observed here.

So our question is which one should we use in each case and why?

Ada_Drivers_Library and the run-times are two separate projects and we use svd2ada in a different way for multiple reasons. The main one is that run-times are more standalone piece for one specific case, where Ada_Drivers_Library is a library that can be used on many different platforms.

For Ada_Drivers_Library, we use the following switches "--boolean --base-types-package HAL --gen-uint-always". You should add your add your platform to this Makefile. Ada_Drivers_Library also potentially uses all the packages from the SVD where the run-time BSP only uses some of them.

For the run-time BSPs, we use the following switches "-p Interfaces.<MCU_FAMILY_NAME>". <MCU_FAMILY_NAME> will be LPC in your case. And for the run-time, we don't keep the packages that are not used. For instance on STM32, we only keep: SYSCFG, UART, PWR, RCC, FLASH and GPIO.

By the way, we are going to change a little bit the BSP scheme in the coming weeks.

I hope this gives you a better understanding, don't hesitate to ask more questions.

Thanks,

@martinmarcos
Copy link
Author

I prefer that you fix the vendor SVD files and check them in the svd2ada repo. The idea is to keep the process 100% automated so that if we improve code generation, we can regenerate the files without any manual action. Patch the sources not the binary :)

Ok. Sound like the correct way to do things. We are looking into this as of now.

Can you elaborate on this? I had a look at the generated code, it looks similar to what we have with the STM32s.

Ok. So on the STM32s you have a clean and neat way to match each physical port and pin combination to the pin and port of the internal GPIO peripheral. That's because it's essentially the same. The pin muxing peripheral and the GPIO peripheral are essentially the same peripheral. For each pin you can select the mode: gpio out, gpio in, alternate function or analog function. If you select the alternate function mode, then you can mux out to 16 possible alternate functions for that pin other than GPIO. On top of that, on the STM32 you have the consistency that each port has the same amount of pins.

That is not the case in LPC43. The LPC43 has 16 ports, 0 through F, which in the datasheet are referred to as "pin groups", and not all pin groups have the same amount of pins. Pin group 0 for example has 2 pins, pin 0 and pin 1, while pin group 1 has 21 pins, pins 0 through 20. The System Control Unit, the SCU, is the peripheral that does the pin muxing. Each pin can be configured with 8 alternative functions, one of which can be the GPIO function. Not all pins are mapped to a GPIO, and pins that are mapped to GPIOs are not all mapped on the same function: some GPIOs are mapped on function 0 while others are mapped on function 4. To make things worse the GPIO peripheral has it's own port and pin numbering scheme that follows no correlation to the numbering of the SCU, they are mapped completely arbitrarily. In the case of the SCU peripheral, each pin is configured through its associated SFS register. Each SFS register has a MODE field which configures the internal peripheral to which the pin is multiplexed. The rest of the fields of the SFS register configure the electric behavior of the pin; things like pull-up and pull-down resistors, slew rate, drive current, etc. In the case of the GPIO peripheral, each pin is configured by several arrays of registers, all of which are addressable through the GPIO's port and pin combination.

From what we observed, all the subprograms of the GPIO driver of the Ada_Drivers_Library operate with the GPIO_Point object. In the case of the STM32 the GPIO_Point object is a record composed of an access to a GPIO_Port variable type and a GPIO_Pin variable. The GPIO_Port type is just an extension of the GPIO_Peripheral type defined in the STM32_SVD.GPIO package. This is all that is needed in the case to STM32 to unequivocally configure a pin to work as GPIO, to set its direction and read or write its value. In the case of the of the LPC43 we need more information. So if we were to reference each GPIO pin with the SCU's pin group and pin combination (since this is the notation we would find on an schematic), first of all we would need to know if the pin can be used as a GPIO. Secondly, we would need some way to associate the pin group and pin combination to the pin's SFS register in order to configure its electric behavior. We would also need to know which of the pin's functions is the GPIO peripheral multiplexed on. Finally, we would need the GPIO's port and pin number associated to that SCU pin.

The solution we had drafted was to make the GPIO_Point object a record type composed of an access to an SFS register, a MODE field variable, a GPIO Port variable and a GPIO Pin variable. So in the Device package we could have a GPIO_Point constant for each SCU pin group and pin combination. But in order to be able to declare an access type to an SFS register type we need all SFS registers to be of the same type and that's the problem we have with binding files that svd2ada generates from the vendor's svd file. Svd2ada declares 20 different types of SFS register types for what are practically the same type of register. In fact there is only 3 types of SFS registers and that is because there are 3 types of pins: normal-drive pins, high-drive pins, and high-speed pins. The majority of the pins are normal-drive pins, but the few that are high-drive or high-speed pins are assigned to a pin group and pin arbitrarily. The SFS registers of the 3 types of pins are practically the same, they only differ from each other by a pair of fields. We fixed this manually by declaring the SFS register type as a variant record type whose variant part depends on the type of pin it is. This way, all SFS registers are of the same type but an attempt to access a field that doesn't belong to the pin type raises a constraint error. We don't have the slightest clue how we could achieve an svd2ada generated binding with a structure like this one by modifying the svd file. We are going to start looking into it.

On other hand, if you have any suggestion on how we could adapt the GPIO driver code to the structures that svd2ada generated from the unedited vendor's svd file, we would be thrilled to hear them!

Regards.

@Fabien-Chouteau
Copy link
Member

Fabien-Chouteau commented Jul 13, 2017

Thanks for the explanation!

I think it's similar to the problem we had with STM32 timers. There are different kinds of timers (16 bits, 32 bits) with slightly different registers.
What @pat-rogers did is to copy part of the SVD generated code that works for all timers and use only that. Then he used contracts to tell users if a given operation is only valid for 32bits timers.

You can have a look here STM32.Timers.

We fixed this manually by declaring the SFS register type as a variant record type whose variant part depends on the type of pin it is.

And it sounds like what you did is similar, so I would say it's a good solution.

This way, all SFS registers are of the same type but an attempt to access a field that doesn't belong to the pin type raises a constraint error.

Is the code on GitHub? I'd like to have a look. Variant record are different than C unions, you will get a constraint error if you try to access a field that is not defined for the actual variant of the instance you are manipulating.

We don't have the slightest clue how we could achieve an svd2ada generated binding with a structure like this one by modifying the svd file. We are going to start looking into it.

Forget what I said, given the situation your solution is more appropriate :)

This indeed a difficult situation but it will be interesting to see if the Ada_Drivers_Library interfaces are compatible with this very different architecture.

Thanks for investigating this!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants