Attempting to manually port a KDS based design into MCUXpresso. Just now starting to use/explore V11.1.1
I expected there would be some differences, but am sort of shocked that all the register definitions defined for the particular device header, in this case for device MKL25Z4.h, are not complete?
That is, all the accessor constructs appear to be present and the same or similar as that used in KDS and CW, but the final Register Instance Definitions aren't defined?
What am I missing?
Solved! Go to Solution.
Not sure what you mean, but: the MCUXpresso SDK is using a different concept from the previous peripheral header files: it uses structs as peripheral description:
typedef struct {
__IO uint32_t PDOR; /**< Port Data Output Register, offset: 0x0 */
__O uint32_t PSOR; /**< Port Set Output Register, offset: 0x4 */
__O uint32_t PCOR; /**< Port Clear Output Register, offset: 0x8 */
__O uint32_t PTOR; /**< Port Toggle Output Register, offset: 0xC */
__I uint32_t PDIR; /**< Port Data Input Register, offset: 0x10 */
__IO uint32_t PDDR; /**< Port Data Direction Register, offset: 0x14 */
} GPIO_Type;
Access is through SDK API calls where you pass a pointer to the struct, and the SDK driver accesses the fields, e.g.
void GPIO_PinInit(GPIO_Type *base, uint32_t pin, const gpio_pin_config_t *config)
{
assert(config);
if (config->pinDirection == kGPIO_DigitalInput)
{
base->PDDR &= ~(1U << pin);
}
else
{
GPIO_WritePinOutput(base, pin, config->outputLogic);
base->PDDR |= (1U << pin);
}
}
This is different from the 'legacy' way where you had bitfield level access. There are pros and cons for each approach, but to me the new one is more portable (bitfields are not portable) and because all the accesses are done inside the SDK functions it is not a problem for the application.
But if you try to port an existing (using legacy accesses) application to the SDK world, this is not easy: I rather recommend to keep it the old way and use the new way for new applications and using the SDK API instead.
Is this what you mean?
I hope this helps,
Erich
Not sure what you mean, but: the MCUXpresso SDK is using a different concept from the previous peripheral header files: it uses structs as peripheral description:
typedef struct {
__IO uint32_t PDOR; /**< Port Data Output Register, offset: 0x0 */
__O uint32_t PSOR; /**< Port Set Output Register, offset: 0x4 */
__O uint32_t PCOR; /**< Port Clear Output Register, offset: 0x8 */
__O uint32_t PTOR; /**< Port Toggle Output Register, offset: 0xC */
__I uint32_t PDIR; /**< Port Data Input Register, offset: 0x10 */
__IO uint32_t PDDR; /**< Port Data Direction Register, offset: 0x14 */
} GPIO_Type;
Access is through SDK API calls where you pass a pointer to the struct, and the SDK driver accesses the fields, e.g.
void GPIO_PinInit(GPIO_Type *base, uint32_t pin, const gpio_pin_config_t *config)
{
assert(config);
if (config->pinDirection == kGPIO_DigitalInput)
{
base->PDDR &= ~(1U << pin);
}
else
{
GPIO_WritePinOutput(base, pin, config->outputLogic);
base->PDDR |= (1U << pin);
}
}
This is different from the 'legacy' way where you had bitfield level access. There are pros and cons for each approach, but to me the new one is more portable (bitfields are not portable) and because all the accesses are done inside the SDK functions it is not a problem for the application.
But if you try to port an existing (using legacy accesses) application to the SDK world, this is not easy: I rather recommend to keep it the old way and use the new way for new applications and using the SDK API instead.
Is this what you mean?
I hope this helps,
Erich
Yes, you got it.
If you were not sure by what I meant with the term "Register Instance Definitions", just copy it and paste into a legacy peripheral header file search. This is the exact terminology used. In the comments of course.
After comparing and studying the differences between the two peripheral header docs, (actually almost identical, certainly in using stuct's), I managed to see how to do a simple edit to get it to compile. e.g.
Legacy:
GPIOB_PDDR |= GPIO_PDDR_PDD(0x00040000);
Newer:
((GPIOB)->PDDR) |= GPIO_PDDR_PDD(0x00040000);
also;
Legacy:
PORTB_PCR18 = (uint32_t)((PORTB_PCR18 & (uint32_t)~(uint32_t)(
PORT_PCR_ISF_MASK |
PORT_PCR_MUX(0x06)
)) | (uint32_t)(
PORT_PCR_MUX(0x01)
));
Newer:
((PORTB)->PCR[18]) = (uint32_t)((((PORTB)->PCR[18]) & (uint32_t)~(uint32_t)(
PORT_PCR_ISF_MASK |
PORT_PCR_MUX(0x06)
)) | (uint32_t)(
PORT_PCR_MUX(0x01)
));
As you can see from above, the only portion that changes is the reference to the actual register assignment. All the mask constructs are the same. But based on your examples to me, I'm guessing that this is not the "preferred" new paradigm. Also I don't know if this edited code actually works. I just know that it compiles without error.
However, I ran into problems when trying to edit config writes to the NVIC. Of course, this is part of CMSIS/Arm documentation and more murky to me.
I think I get your reasoning that it makes code more portable, at least I'll trust your judgement.
It does bother me that there is now no direct terminology linkage to the device Reference Manual. That is, I would study a devices peripherals and registers using the pdf manual. I could then copy and paste a registers name into a header search, verify it and start using it. Seems like a step backward.
Also, you mentioned "bitfield level access". This reminds me of another gripe I have with 'Xpresso. When playing around with the "Pins" configuration tool, I finally figured out that they use the term "Pin" for both the actual package pin, as well as register configuration BITS! These aren't PINS, they're BITS! At least that is the way the Reference Manual rightly refers to them. Talk about super confusing.
From what I'm seeing, the newer tools are digressing from the device Reference Manual. So I guess the new bibles to use are the "MCUXpresso SDK API Reference Manual"?
Thanks for your reply and support.
Gregg