Migrating to MPLABX from studio - Page 1
Forum section: electronics / general

author: Simon
author_rank: Unknown
timestamp: June 23, 2025, 10:40:37 am
content: Yes, I know I am nuts but in order to continue to develop with microchip parts I have to use MPLABX.I now have to start converting my own written libraries over to hopefully work with my current SAMC21 and my future PIC32CX-SG which shares same peripherals and registers.So my understanding is that the CMSIS packs or whatever microchip prefers to call them are now completely different. Instead of bit fielded structures there are just structures of the registers and macros for each value. I also see that macros for peripheral instances where for whichever chip in the family you use you can setup an array of pointers to the instances are gone. This was done by there being a definition for each chip variant for the number of instances and a definition for the assignment of a list of pointers to the newly setup array:Code:#define TC0 ((Tc *)0x42003000UL) /**< \brief (TC0) APB Base Address */#define TC1 ((Tc *)0x42003400UL) /**< \brief (TC1) APB Base Address */#define TC2 ((Tc *)0x42003800UL) /**< \brief (TC2) APB Base Address */#define TC3 ((Tc *)0x42003C00UL) /**< \brief (TC3) APB Base Address */#define TC4 ((Tc *)0x42004000UL) /**< \brief (TC4) APB Base Address */#define TC_INST_NUM 5 /**< \brief (TC) Number of instances */#define TC_INSTS { TC0, TC1, TC2, TC3, TC4 } /**< \brief (TC) Instances List */So is this really what I am facing? The ability to use the above to create code where:Code:static Tc* instance = TC_INSTS ;instance->..........Allows me to write code that works on any peripheral instance.Would it be better to just copy the old CMSIS pack for the SAMC21 and reference that instead and keep my code as it is?But then when I want to use this code with another chip I will have to practically write the CMSIS myself or at least take a copy of the SAMC21 one and update it to the new chip.I've gone as far as I can now in making my libraries work with the new pack, now I will have start writing definitions that are for the chip myself.This is all on the assumption that microchip studio will be ditched eventually so I have to move and that newer chips and tools will not be added to studio so I have no choice and nowhere else to go that is a simple to move to.

author: westfw
author_rank: Super Contributor
timestamp: June 25, 2025, 01:44:34 am
content: QuoteCan't you just do:Code:static tc_registers_t* instance[] = {#ifdef TC0_registersTC0_REGS,#endif#ifdef TC1_registersTC1_REGS,#endif#ifdef TC2_registersTC2_REGS,#endif#ifdef TC3_registersTC3_REGS,#endif#ifdef TC4_registersTC4_REGS,#endif};#define TC_INST_NUM (sizeof(instance)/sizeof(instance))You'd still have to deal with the elimination of the ".bits/.reg" and the name changes, but that would give you the flexibility you seem to want.I have mixed feelings about the changes. On the one hand, the .bits/.reg syntax was not particularly compatible with the CMSIS standard as I understand it, and was prone to causing certain bugs and misunderstandings. On the other hand, the new names, while nicely "standardized" in their naming scheme, are awfully verbose :-(And of course the magnitude of the change is quite annoying...

author: westfw
author_rank: Super Contributor
timestamp: June 25, 2025, 06:02:05 am
content: QuotePS: this is the sort of thing that's pretty trivial to do with a good editor, or a very short and simple program...

author: Simon
author_rank: Unknown
timestamp: June 25, 2025, 06:46:33 am
content: Yes I have ended up recreating the arrays myself but the idea of making them conditional is a good one, I should do that.How do the bitfields cause bugs? do they not always get interpreted in the right order? if that is the case what about the register structure itself? or is that less sensitive?.I have managed to get the project to compile but not work. So I am working round everything to see if I can find a mistake caused by the changes being acceptable in terms of C/C++ but not an actual reflection of the chip.MPLABX is extremely annoying. The pixelation of the fonts on my 4k screen is giving me a headache and from memory there is no fix for that, I have tried many times before, it was one of the main reasons for not using it. It constantly flags things that are not errors and compile perfectly fine.

author: tooki
author_rank: Super Contributor
timestamp: June 25, 2025, 10:03:27 am
content: Quote from: Simon on June 25, 2025, 06:46:33 amI’ve been using MPLABX on 4K screens since around 2022. Just go into the executable’s properties and set the high-DPI settings to “Scaling performed by:“application”. Then in MPLABX, change the font size for the terminal windows and anywhere else it appears too small.

author: Simon
author_rank: Unknown
timestamp: June 25, 2025, 10:16:52 am
content: I've had lots of fun with it in the past, maybe now that I can launch it as an admin that might help.

author: tooki
author_rank: Super Contributor
timestamp: June 25, 2025, 10:22:55 am
content: Quote from: Simon on June 25, 2025, 10:16:52 amThat’s got nothing to do with it.

author: Simon
author_rank: Unknown
timestamp: June 25, 2025, 11:51:13 am
content: Nope it hasn't. I remember the dilemma now, do I want text to look right in the code editing window or do I want to be able to see the icons and dialog box texts. Is there any way to get the rest of the interface to show the right size?

author: jc101
author_rank: Frequent Contributor
timestamp: June 25, 2025, 05:58:38 pm
content: Quote from: tooki on June 25, 2025, 10:03:27 amEasy fix for MPLAB om hi-res displays, for Windows anyway...Open the mplab_ide.conf in Notepad. You will need to run Notepad as admin. This can be found in...QuoteAdjust the v6.25 for your installed version.find the entryCode:default_options=and addCode:-J-Dsun.java2d.dpiaware=trueas the first parameter.You should then find everything nice and crisp on high res displays. It has worked for me on 4K and 5K displays. First thing I do when installing a new copy of MPLABX is add this to the config file.

author: westfw
author_rank: Super Contributor
timestamp: June 26, 2025, 05:32:58 am
content: QuoteIt has to do with unexpected RMW when dealing with IO registers with non-standard write behavior (eg "write a 1 to this bit to clear it.")I don't remember the exact case that came up; some peripheral error status register, used like:Code:periph.errreg.bits.error1 = 1; // clear error1.This ends up implemented as reading the whole "errreg", setting the "error1" bit, and writing it back. But that means that OTHER bits in errreg that read as 1 also get cleared.And of courseCode:peripher.config1.bits.dosomething = value;peripher.config1.bits.dosomethingelse = value2;peripher.config1.bits.doanotherthing = value3;ends up being much more bloated than i could be withCode:peripher.config1.reg = (value<<valpos)|(value2<<val2pos)|(value3<<val3pos);because "config1" is volatile and each bitfield set is going to require a separate read and store.QuoteYes. I find it... "amateurish" - windows popping up and self-maximizing for no good reason, needing to hunt all over to find menu options that weren't where you'd think they'd be, stuff with weird names and labels... Sigh. Sort of what you'd expect from an OSSW project that had a bunch of people working on it that never "communicated" very well about the overall look and feel behavior...

author: Simon
author_rank: Unknown
timestamp: June 26, 2025, 07:53:20 am
content: Ah yes the reset with 1 registers. I fell foul of that early on and quickly learnt that I can read the bit with a .bit member nut not write. To be honest you can still make that mistake if you are not careful as you get into the habit of making every write to a register with |=.I have noticed that my RAM requirement has dropped significantly and my code is now working so it is not because I have an error that is rendering much of it unused and optimized out, that is neat, I think it may be something to do with the compiler working out how much stack is actually needed.As a program MPLAB.X is utter trash. I know much of that may come from the netbeans that it is based on but cmon guys, that was no way to do the layout of the registers when debugging. It's slow to scroll and really with things like a SERCOM it is a mess. OK it may need to be called different things if it is a UART, I2C or SPI but to have separate SPIM and SPIS is silly, even the datasheet does not differentiate so it is literal duplication on what is already and impossible to sort information overload.When I start it and see things like a balloon saying PICKIT5 is found I wonder as to who they subbed this out to.

author: jc101
author_rank: Frequent Contributor
timestamp: June 26, 2025, 07:58:50 am
content: They are working on extensions to VS Code, as a way to move away from Netbeans. It's still in beta, but that seems to be where the development work is heading at the moment.

author: Simon
author_rank: Unknown
timestamp: June 26, 2025, 08:13:09 am
content: Quote from: jc101 on June 26, 2025, 07:58:50 amSo I am partly wasting my time then. OK I probably needed to update my standard code that accesses registers but I am still going round in circles with the hidpi thing. Microchip say:https://developerhelp.microchip.com/xwiki/bin/view/software-tools/ides/x/configuration/monitors/to set -J-Dsun.java2d.dpiaware= false not true, either way it won't work so I still think it is the fact that I am not a full admin user that is getting windows nickers in a twist.

author: jc101
author_rank: Frequent Contributor
timestamp: June 26, 2025, 08:34:45 am
content: I spent a long time trying to get MPLAB X usable on a 4k+ display. Adding that setting seemed to be the optimal for me. The screen shot is from my PC, which has a 5120 x 2160 monitor. I prefer one widescreen monitor than the vertical bar the down the middle of two, three would take up too much space!Downside is you do need admin rights to be able to save the edited file.edit: the posted .png thumbnail here isn't as crisp as I see it, trying to post it inline. Though even that isn't as sharp as it looks here.

author: Simon
author_rank: Unknown
timestamp: June 26, 2025, 08:44:39 am
content: Well some panels can be scaled by holding CTRL and scaling, the memory watch panel seems to do this, the project properties does it. But a lot of other stuff does not and I wish I could find a setting for it. Micropchip allude to it but link to the netbeans home page instead of an explanation.

author: Simon
author_rank: Unknown
timestamp: June 26, 2025, 03:36:54 pm
content: Well first discovery, you can't do debugging with MPLAB.X and the PICKIT5 whilst running Maxon's Escon Studio with a motor driver connected. No idea which company it as fault as they are as hopeless as each other.The debugger just stops working once the session is started, break points won't work and you cannot pause or stop the session, it just locks up. You have to restart the program having unplugged everything.

author: Simon
author_rank: Unknown
timestamp: June 27, 2025, 07:42:13 am
content: It's the PICKIT5, it does not like its negative output connected to its negative input which happens if another "thing" including an oscilloscope ground is connected. Same problem with the Atmel ICE if I remember correctly.

author: cv007
author_rank: Frequent Contributor
timestamp: June 27, 2025, 10:12:23 am
content: Are you sure the newer packs do not still have the bitfields?static Tc* instance = TC_INSTS ;instance->..........Your n at the moment is presumably a variable passed to a function. Skip the n and use a Tc* directly-#define my_tc 0static void func(uint8_t n){ inst-> ... }func( my_tc );vsstatic Tc* my_tc = TC1;static void func(Tc* inst){ inst-> ... }func( my_tc );The first most likely never validated n, the second cannot be used with an undefined TCn pointer. The first could have my_tc defined as 9, but you won't get away with using TC9 for the second as the define does not exist.QuoteThe bitfields at first seems like a great idea, and usage does become easy. But, the hiding of what actually happens behind the scenes can lead to problems- you see a simple assignment in the code but the compiler does not generate a simple write.The big package of define names manufacturers produce I think is not very useful. These defines are not always easily distinguishable and are easily misused, with no one around to check whether you have used the correct define (even if asserts are everywhere, asserts can still pass when a wrong define is used).Either in the case of using bitfields, or not, your low level code should only be contained in functions. Inside the function, you will have to deal with things like rmw whether visible or not (using bitfields), so at that point the bitfields are not a great help as it also requires you to think about any resulting effects.Some options-Code://ideal usage I think, using provided peripheral register structs//and instance defines (TC1, TC2, etc.)//create your own local enums as needed, skip the manufacturer defines//you need a datasheet to refer to in either caseenum {MODEbm = 3<<0, //bitmask to clear mode bitfieldMODE8bm = 1<<0, //bitmask to set mode to count8ENABLEbm = 1<<1 //enable tc}; //ctrlavoid tc8_off(Tc* inst){inst->COUNT8.CTRLA.reg &= ~ENABLEbm;}void tc8_on(Tc* inst){inst->COUNT8.CTRLA.reg = (inst->COUNT8.CTRLA.reg & ~MODEbm) | ENABLEbm | MODE8bm;}Same, but using bit defines instead of self created enums-Code://using existing defines for register bits (their meaning becomes a question in many cases,// so you end up having to look them up and figure out which on you actually want)// and this is what you have to decipher-// #define TC_CTRLA_ENABLE_Pos 1 /**< \brief (TC_CTRLA) Enable */// #define TC_CTRLA_ENABLE (_U_(0x1) << TC_CTRLA_ENABLE_Pos)// #define TC_CTRLA_MODE_Pos 2 /**< \brief (TC_CTRLA) Timer Counter Mode */// #define TC_CTRLA_MODE_Msk (_U_(0x3) << TC_CTRLA_MODE_Pos)// #define TC_CTRLA_MODE(value) (TC_CTRLA_MODE_Msk & ((value) << TC_CTRLA_MODE_Pos))// #define TC_CTRLA_MODE_COUNT16_Val _U_(0x0) /**< \brief (TC_CTRLA) Counter in 16-bit mode */// #define TC_CTRLA_MODE_COUNT8_Val _U_(0x1) /**< \brief (TC_CTRLA) Counter in 8-bit mode */// #define TC_CTRLA_MODE_COUNT32_Val _U_(0x2) /**< \brief (TC_CTRLA) Counter in 32-bit mode */// #define TC_CTRLA_MODE_COUNT16 (TC_CTRLA_MODE_COUNT16_Val << TC_CTRLA_MODE_Pos)// #define TC_CTRLA_MODE_COUNT8 (TC_CTRLA_MODE_COUNT8_Val << TC_CTRLA_MODE_Pos)// #define TC_CTRLA_MODE_COUNT32 (TC_CTRLA_MODE_COUNT32_Val << TC_CTRLA_MODE_Pos)void tc8_off(Tc* inst){inst->COUNT8.CTRLA.reg &= ~TC_CTRLA_ENABLE;}void tc8_on(Tc* inst){inst->COUNT8.CTRLA.reg = (inst->COUNT8.CTRLA.reg & ~TC_CTRLA_MODE_Msk) | TC_CTRLA_ENABLE | TC_CTRLA_MODE_COUNT8;}...and I think one can see that the defines, rather than a big help, simply require you to verify you are using the correct one. Now you have additional work- find from the datasheet what you want to do, try to find the value in the defines and make sure you have the correct one, put it in your code. Now a week later when something doesn't work right you are back to comparing defines to datasheet and your code. The names are supposed to indicate their purpose, but naming doesn't always work as planned (is the TC_CTRLA_MODE_COUNT8 a bitmask, a value, or was I supposed to shift on my own, etc.).The enums you create are local to only where they are needed (when possible) and do not pollute the global namespace. If an enum is required to be in your header, then you have to deal with naming again. But you will have your values named to what makes sense to you and its easy to create comments for these values. If the values need to be questioned, you are then only going from the datasheet directly to your code with no intermediate lookups needed (manufacturer defines).Now with bitfields-Code://if using bitfields, you have to think about what code is being produced//behind the scenesvoid tc8_off(Tc* inst){inst->COUNT8.CTRLA.bit.ENABLE = 0; //reg &= ~ENABLEbm;}void tc8_on(Tc* inst){inst->COUNT8.CTRLA.bit.MODE = 1; // reg = (reg & ~MODEbm) | MODE8bm;inst->COUNT8.CTRLA.bit.ENABLE = 1; //reg |= ENABLEbm;}In all cases, your usage is the same. You created higher level functions, most are simple/easy/small one time creations and require some thought when created but for the most part you are then done with the details of how it works. The bitfields end up being not that helpful simply because you are not doing a lot of duplicate register writing in your functions (if a function needs to turn off the tc for example, you call the function already in place instead of duplicating code to do the same thing, and the compiler will optimize these calls to inline code in most cases when the function is local/static).static Tc* my_tc = TC1;tc8_off( my_tc );

author: Simon
author_rank: Unknown
timestamp: June 27, 2025, 11:37:22 am
content: As always understanding how it works is essential no matter which way you do it. Bit fields are nicer but if they are not being supplied well OK. I want to write code that will work on the same peripheral in different chips so sticking with what the manufacturer provides is best as I assume that same peripherals on a different chip will have the same register names and layouts.In terms of bit fields or not avoiding issues with status registers where writing a bitfield will cause problems, you end up with similar problems without them if you are not careful. The macros supplied are written so that you can set the register up in one go with everything, but as soon as you want to change a value, that is change a value that might have already been written, now you have to manually create the RMW code that the compiler would have done for you in a bit field. That is not simple. I actually find myself using the bit mask macros more than the set value macros. This is because you have to "|=" to set a bit but "&=" with the inverse of the mask to clear a bit, if a specific multibit value is to be written you have to do both.All taking bitfields out has done is to increase the amount of code I have to write, The whole way in which programs are structured is to create blocks that get reused, that is all the bitfields did, it was just at compiler level instead of a function in the headers - oh yea, I'm writing those inline functions myself now, because why have the compiler help me?

author: westfw
author_rank: Super Contributor
timestamp: June 29, 2025, 12:10:23 am
content: QuoteQuite sure. MPLABX only "supports" packs version 3.x and greater.I think the bitfield-heavy structures were last present in v2 packs (you can still download a v2.0.5 pack for SAMC20)

author: cv007
author_rank: Frequent Contributor
timestamp: June 29, 2025, 08:22:39 am
content: QuoteI assumed the CX was some newer mcu, and saw they use a conditional define to select which register style to use. But those packs are versions 1.x. I now see C21 has 3.x which have eliminated the bitfields.The project options in MPLABX will allow selecting which pack you want to use, so probably already 'sees' the pack which was used by studio.For an example where bitfields become unreadable, and almost unusable-https://raw.githubusercontent.com/renesas/fsp/refs/heads/master/ra/fsp/src/bsp/cmsis/Device/RENESAS/Include/R7FA2L1AB.hso you end up either using their higher level driver and don't touch registers, or you simply write your own register struct for a peripheral which will end up being a dozen lines of code and readable.

author: Simon
author_rank: Unknown
timestamp: July 01, 2025, 04:46:29 pm
content: My issue is that I am writing the low level code and as I move to a newer chip I want to take as much code as possible with me rather than keep rewrting it and keep it the same code base not same but different versions of the same for each chip.I don't see the point in fumbling through the graphical stuff to set a chip up the same way over and over with maybe slight changes. If I interact with say a timer as a PWM generator I prefer to create a C++ class per channel and that handles it anyway. Yes I will have defines that cut in the right code for the chip in use, guess how the graphical stuff does it.Either way I am not too fussed how it is done, I just need to base on something that will not change later and is common across chips.

author: westfw
author_rank: Super Contributor
timestamp: July 01, 2025, 09:34:14 pm
content: QuoteAh. You want to write actually useful "abstractions", rather than the "does so much that it needs a GUI that changes every 6 months, and doesn't really "abstract" things at all" code generator/HAL provided by most vendors. ("Atmel Start" was one such horror, and I assume that you've read at least a little of the "Is STM Cube awful" thread, as they embark on at least their 3rd major re-imagining of what a vendor library ought to look like.)

author: Simon
author_rank: Unknown
timestamp: July 02, 2025, 05:00:41 pm
content: I won't touch ST chips as they are just cheap crap, well I suppose you get what you pay for. The CAN controllers on their smaller chips are not very useful. PC programmers won't see the difference but you need a larger one before you get the BOSCH MCAN controller. The SAMC at £1.5 has 2x BOSCH MCAN controllers. The microchip MCP2515 costs the same, so you micro is free. On the SAMC I can run the whole chip off an RTC crystal if I want by using it as the input to the PLL, this gives me up to 96MHz that can be divided by 2 for the CPU and by 3 for the ADC input. It's so perfect, like someone thought about it on an M0 chip, it's not about the processor, it's more about the peripherals. The ST chips will force you to use 2 crystals if you want both high and low frequency clocks to be accurate, all for the sake of a few transistors and designers with some vision. To me this makes the "more expensive" atmel part actually cheaper.I never understood Atmel start, microchips attempt is abysmal. Regardless of who's it is all you end up with is a thing that writes code for you that is not in your code. I find it easier to set things up myself. I've bought into C++ classes massively, it just makes the code so much more logical and that includes the peripherals. All I need to do is create the object instance with the same settings I'd be putting into some silly form.I tried the microchip "thing" and it set the non volatile memory wait states to 3 instead of 2 as per datasheet recommendations so yea. Basically I'm writing my own version in actual code.

author: cv007
author_rank: Frequent Contributor
timestamp: July 03, 2025, 09:33:27 am
content: QuoteCreate your own register struct inside the class where it will be used. Its not a big job and it will be your code, located in the same place its used. The same applies to any enums, whether for private use, or for a user of the class (function arguments, which will be type checked by the compiler). They will also be located where the code is, so when using your code you have a single place to look for available functions and arguments in the form of enums in many cases.Unless you start including the manufacturer header in your code, name collisions will not be a problem. If you start to mix your own code with manufacturer defines, then those defines may start colliding with your own names (although maybe less likely since they have their own collision problem so they end up with names longer/more descriptive than what you would use/need).Simple example of creating your own register struct inside the class-https://godbolt.org/z/vjMPo6Y41not a big job, and it will not depend on the manufacturer provided naming scheme (which 'pack' is in use). Its yours, and changes only when you change it.Whether one wants to do this or not is a decision that can be made as needed. You do not have to write code for every peripheral before its needed, so can do this as peripherals are used. If you create a peripheral class, simply spend the 10 minutes to create your own register struct.

author: Simon
author_rank: Unknown
timestamp: July 10, 2025, 10:33:14 am
content: I'm trying to look at the contents of the RWW memory with a PICKIT5 on a SAMC, sounds like this is a bit convoluted in MPLABX.