Giter Club home page Giter Club logo

Comments (3)

Fabien-Chouteau avatar Fabien-Chouteau commented on July 21, 2024

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,

from ada_drivers_library.

martinmarcos avatar martinmarcos commented on July 21, 2024

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.

from ada_drivers_library.

Fabien-Chouteau avatar Fabien-Chouteau commented on July 21, 2024

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!

from ada_drivers_library.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.