Microchip woes! - Page 1
Forum section: electronics / general

author: nali
author_rank: Frequent Contributor
timestamp: January 25, 2016, 10:28:59 am
content: is happening at Microchip?? I've occasionally used PICs with Mikropascal for years for trivial projects so I've decided to use PIC as the controller for my smart PSU (hobby) project and use C code. So I download the latest MPLAB & XC8, here's how it goes:From the zillions of devices I choose a 16F1779 from Farnell, partly because it's got an inbuilt 10-bit DAC onboard. It's not supported by XC8So use a 18F25K22 which I had in my parts box, and order a cheap SPI DAC to use with it. Start a new project, use the MPLAB Code Configurator to set a GPIO pin and write a couple of lines of code to toggle it. OK, that was easy. Now I add a rotary encoder to RB0/RB1 so I can start playing with interrupts.There's no gpio interrupts in MPCC. Or rather there is a blank column with no tickyboxes to select them. Now, I don't have a problem manually writing an interrupt handler but as this is a new environment to me I'd rather use the default tools while I climb the learning curve, and who knows if MPLAB will overwrite any of my code? From what I've seen so far I wouldn't be surprised.I decide to look on Microchip's forums, try searching for IOC. Search just displays a "Searching...." dialog for a few seconds then sweet FA, it seems to be broken.I decide to sign up to post a question. Enter my details and a password and I get "Invalid password" (there is no criteria mentioned on the sign in page!). My initial p/w was just letters so I add some digits and try again. Now the page just reloads, no error displayed. After trying a couple of times using Chrome I try the same using IE with the same result. No email received, so that appears to be broken.this project's going back on the shelf for now. Maybe I'll forget about digital control and use good old fashioned analogue pots and meters, I dunno, I'll decide later....

author: hans
author_rank: Super Contributor
timestamp: January 25, 2016, 10:36:01 am
content: You also need to download the "extended part support" libraries for compilers in order to compile for them. Unfortunately the 16F1779 is not in pack 1.35BQuoteYou probably have to wait a few months in order to get this part supported.I rest my case.As for the "code configurator", hmm how useful is it really? I always find it hard how you could "abstract" the concept of an interrupt in a code generator. I can understand it's useful to get basic init & clock stuff running, but interrupts.. it's not really doing much work.. just generating some framework code.I don't use it. Just write the C code yourself. MPLAB X is not going to "override" code; it may include some C startup and a linker file in the background but that is happening in every compiler. You can replace it in the linker settings, so no woes there.I would always search using google. You get results for Microchip forums, but as well others. It's faster & more content.

author: Xenoamor
author_rank: Regular Contributor
timestamp: January 25, 2016, 11:01:37 am
content: I'd just start with an atmega168 which also has a 10bit ADCThere's a wealth of tutorials for the atmega168/328 and it has a strong community even if a bit fierce.Personally I'm just a fan of the well documented datasheet

author: Monkeh
author_rank: Super Contributor
timestamp: January 25, 2016, 11:42:30 am
content: http://www.microchip.com/forums/m908793.aspxQuote

author: dannyf
author_rank: Super Contributor
timestamp: January 25, 2016, 12:04:38 pm
content: Your experience is not unique, the microchip software teams just suck. There is no kinder way of putting it.

author: nali
author_rank: Frequent Contributor
timestamp: January 25, 2016, 12:19:47 pm
content: Quote from: Monkeh on January 25, 2016, 11:42:30 amYeah I saw that - No mention of when though. Considering 1.35B was only released in September I'm not going to hold my breathI'll probably either forget the convenience "tools" & write all my code manually using the datasheet, or have a play with some Atmels which I need to have a look at anyway for a legacy project at work.I was more frustrated at having wasted an evening reinstalling unfamiliar software because MPLAB wasn't seeing XC8 only to find I had picked an unsupported part - this being AFTER Googling & finding a whole load of posts saying I need to followtheseinstructions (outdated link), need to manually register MPLABXC8.dllThen trying to do something the documentation explicitly says I should be able to do. Then a broken forum. The overall impression is pretty cruddy IMHO.Anyways, I feel better now I've had my whinge!

author: Xenoamor
author_rank: Regular Contributor
timestamp: January 25, 2016, 01:20:38 pm
content: My general consensus theses days is to use a text editor with a manufacturers header files and a custom makefile.Means you can quite comfortably sit in your familiar environment and that your code can be compiled many years from now on any OS

author: SteveyG
author_rank: Unknown
timestamp: January 25, 2016, 03:36:23 pm
content: Quote from: Xenoamor on January 25, 2016, 11:01:37 amIMO Microchip have some of the best datasheets, it's just the built in compiler support is not as up to date as the current product line. The device itself is great and has all the features if you are familiar with XC.

author: bktemp
author_rank: Super Contributor
timestamp: January 25, 2016, 04:00:58 pm
content: Quote from: SteveyG on January 25, 2016, 03:36:23 pmYes, but you have to wait about 5 years for a new device until the datasheet covers all the erratas and becomes really usable.And never trust any microchip ADC oder DAC specification unless the datasheet has been updated several times. The specifications typically get worse over time.

author: Monkeh
author_rank: Super Contributor
timestamp: January 25, 2016, 04:15:49 pm
content: The first revision of a datasheet contains the hopes and prayers of the silicon engineers. The final revision contains their tears.

author: Daving
author_rank: Contributor
timestamp: January 25, 2016, 06:43:14 pm
content: Quote from: nali on January 25, 2016, 12:19:47 pm1.36 should be out soon(TM). They tend to come out every 3 months or so to add support for new parts, and push bug fixes. MCC3.0 should also be out soon(TM).

author: Howardlong
author_rank: Super Contributor
timestamp: January 25, 2016, 07:24:07 pm
content: Quote from: hans on January 25, 2016, 10:36:01 amAs with any code generator or translator I've ever encountered in my career it's a mixed blessing.O It's quite buggyO You have to know and understand the peripherals anyway, there is no way around thisO It generates code as a full 8 bit register settings, not using bitfields, therefore it's not easily human-readableO Far, far, far too much useless and unnecessary commentary, especially in the source file headersO Does not generate the most efficient codeO It doesn't support the latest devices, or even some older ones properlyO Peripherals often not fully implemented in the UIO Stupid merge nonsense means your bug fixes are overwritten and so is your application specific code far too easily: there is no clear way to define your own code sections distinct from machine generated nonsense.Having said all that, I do use it sometimes though to generate boilerplate code in a dummy project, possibly even unit test it there, then copy and paste relevant bits into my own code and tidy it up to my own standards (using bitfields for example).O Did I mention it's buggy?Overall, it's a positive, but not by much. I consider it completely useless for maintaining code ongoing for example, it's just too likely it'll scrub your carefully hand coded sections away, and I strongly object to being forced to code up my own stuff in someone else's format. But it's OK for getting a few peripherals initialised, and copying and pasting that code into your own project.O Oh, and it's a quite buggy.Anyone who thinks this is the answer the Arduino crowd's been looking for has been misled. You simply can't ignore the fact that you still have to understand what each peripheral is capable of and its little intricacies.

author: nali
author_rank: Frequent Contributor
timestamp: January 25, 2016, 08:37:10 pm
content: Quote from: Howardlong on January 25, 2016, 07:24:07 pmThat's pretty much what I set out to do. Trying to learn a new i) IDE ii) Language iii) Device at the same time, it's nice to get some sort of framework as a starting point. Not to worry, I'll plod on and find my own way; I've got a flashing LED and I've done a bit of stuff with PICs using MikroPascal including timer & ADC interrupts so it's not the end of the world.

author: Howardlong
author_rank: Super Contributor
timestamp: January 25, 2016, 09:16:34 pm
content: Quote from: nali on January 25, 2016, 08:37:10 pmI did take one of their "Minute" videos which shows someone building a blinky with Code Configurator in about two minutes. So I thought I'd do the same without Code Configurator. I did it in 90 seconds.There is actually little value in those videos other than someone showing how quickly they can use the app in a rehearsed manner. When I tried to repeat what the presenter did, I had to keep stopping the video to keep up, but it was one of the first times I'd used Code Configurator. In reality, making an unrehearsed blinky with Code Configurator would probably take a reasonably seasoned individual five minutes from beginning to end. I can certainly write a blinky without rehearsal or Code Configurator much quicker than that on any PIC form PIC10 to PIC32.

author: Daving
author_rank: Contributor
timestamp: January 26, 2016, 07:39:41 am
content: Quote from: Howardlong on January 25, 2016, 07:24:07 pmThere's a few bugs. Mostly obvious ones, but a few subtle ones.I think it's an okay learning tool. It at least is quicker to learn a new peripheral with MCC + the datasheet than the datasheet by itself. Also, the CLCs lend themselves to a graphical setup.Agreed. It'd be nice if it was a little more verbose. The comments help with this, though.I use code folding in the IDE to hide the comments until I need them. I personally like the functions being documented in the header. It's under tools->options->editor->folding (image attached)True. It favors readability in most cases over pure efficiency. Although some of the code could use improvement in the readability department, too. In general though, premature optimization should be avoided.http://c2.com/cgi/wiki?PrematureOptimizationIt’s harder to read code than to write it.http://www.joelonsoftware.com/articles/fog0000000069.htmlThat's one issue with microchip almost never EOLing parts. The catalog endlessly expands, and there's a limit to what gets supported by new tools out the gate.True. In the 3.0 beta, there is a register view, so you can get full access to all of the peripheral's features, and not just the mainstream ones.MCC could handle dependency injection (and bug fixes) better, so that you don't have to edit the MCC files. Someday

author: Howardlong
author_rank: Super Contributor
timestamp: January 26, 2016, 08:14:21 am
content: The proof of the pudding is in the eating.If I spend more time trying to adapt to a new way of doing things than plodding along as before, then it's a net negative, but you won't necessarily know that until you've had to try to adapt, by which time it's wasted effort.An example of a bug is at it incorrectly sets the clock in the majority of cases for PIC16F183xx. As they don't use bit fields, you have to spend time reverse engineering the machine generated code and debug the OSCCON registers. As setting the clock is one of the most fundamental and tricky parts to even started on a device, one would have hoped they'd get this right, but no. So I had to know all the stuff about how the clock worked, how the various fields in the OSCCON registers worked, and debug their code, so definitely it's a time deficit as soon as it generates bad code.As another example, the I2C interrupt code that's generated is not just a bit of register setting, it's a fairly significant state machine. So do I learn how to use a non-trivial state machine from a jack of all trades code generator, or do I code up my own API? Having seen what's generated, I'm fairly sure I'd rather code up my own and understand what's going on, and save the effort in trying to understand how to use and manipulate my use cases around a machine generated layer.So I'm still on the fence. I think if they'd have used human readable bitfields I'd have been far more positive despite the bugs.They've also fallen into the same traps as the Harmony developers did regarding code generation and merging too. Surely it isn't too difficult to have some tag injected around application specific code that tells the merge algorithm "no touchy" without having to prompt you. This alone makes the code unmaintainable ongoing: sure, generate your boilerplate, but after that no more "help" fiddling with my code thank you.

author: hli
author_rank: Frequent Contributor
timestamp: January 26, 2016, 12:07:56 pm
content: Quote from: nali on January 25, 2016, 10:28:59 amSurely it is there. The 18F25K22 can do IOC only on port RB4-RB7. When you select them for the GPIO module, there are select boxes in the IOC column. (RB0-RB2 can be used for external interrupts too, but the EXTINT module is supported only in the new beta MCC I think.)Make sure to get your facts right before ranting

author: dannyf
author_rank: Super Contributor
timestamp: January 26, 2016, 12:40:46 pm
content: "As they don't use bit fields, you have to spend time reverse engineering the machine generated code and debug the OSCCON registers. "Wow, I'm surprised that someone as advanced and as experienced as you are got stumbed by something this simple.

author: Howardlong
author_rank: Super Contributor
timestamp: January 26, 2016, 01:58:21 pm
content: Quote from: dannyf on January 26, 2016, 12:40:46 pmI don't think I ever said I was stumped, I just don't walk around with the bitfields in my "advanced and experienced" head, but thank you for the flattery.Without using bitfields, the reader, even an advanced and experienced one, must frequently refer back to the DS, which IMHO is time consuming and unnecessary when it could've been written in the code. I assume that it's done that way to improve performance and reduce code size somewhat, but generally setting up peripheral registers is rarely at a pinchpoint in code. Of course, if it weren't so buggy there'd be much less need to do this. An option would be nice to select between bitfield notation and byte-banging.But then I'm sure someone of your calibre already knew that.

author: Daving
author_rank: Contributor
timestamp: January 26, 2016, 04:06:06 pm
content: Since most of what we're talking about is in the initialization code, it's not terribly important that it have the fastest execution. Expanding the statement to a few lines with enums for the assignment options would be nice.So something like this in the header:Code:typedef enum {ADC_ADFM_LEFT,ADC_ADFM_RIGHT,ADC_ADFM_COUNT} adc_adcon1_adfm_t;typedef enum {ADC_ADCS_FOSC_2,ADC_ADCS_FOSC_8,ADC_ADCS_FOSC_32,ADC_ADCS_FRC1,ADC_ADCS_FOSC_4,ADC_ADCS_FOSC_16,ADC_ADCS_FOSC_64,ADC_ADCS_FRC2,ADC_ADCS_COUNT} adc_adcon1_adcs_t;typedef enum {ADC_ADPREF_VDD,ADC_ADPREF_RESERVED,ADC_ADPREF_VREF,ADC_ADPREF_FVR,ADC_ADPREF_COUNT}adc_adcon1_adpref_t;And this in the intialize function:Code:ADCON1bits.ADFM = ADC_ADFM_RIGHT;ADCON1bits.ADCS = ADC_ADCS_FOSC_32;ADCON1bits.ADPREF = ADC_ADPREF_VDD;Instead of:Code:// ADFM left; ADPREF VDD; ADCS FOSC/32;ADCON1 = 0x20;At any rate, the compiler should compile repeated assignments to the same register to one assignment. I'll have to check and see if it does, now that I think about it.Edit: And now that I think about it further, optimizing writes to SFRs could be tricky, since SFRs are written to specifically for their side effects. (Writing 1 to LATB1 stores the 1, but it also sets the pin high).Oring a bunch of values together gets pretty ugly, especially with a 32-bit SFR.

author: nali
author_rank: Frequent Contributor
timestamp: January 26, 2016, 06:11:58 pm
content: Quote from: hli on January 26, 2016, 12:07:56 pmYou're right. I tried RB7 and the IOC options magically appear, although I was initially looking for the external interrupts not IOC. A bit of selective reading on my part not helped by me getting a bit annoyed!

author: bktemp
author_rank: Super Contributor
timestamp: January 27, 2016, 03:38:54 pm
content: Quote from: Daving on January 26, 2016, 04:06:06 pmThat is exactly the problem. The SFRs are volatile, so prohibiting almost any optimization.Microchip did all the SFR bits using bitfields. It is easily readable, but generates a large code, because the compiler needs to read-modify-write every changed bit. So instead of writing a single 8/16/32bit register at once it may read-modify-write 8/16/32bits individually. That may generate 10s of bytes of code instead of a single word.AVR-gcc does not have any bitfields, instead defines for the bitvalue of each setting. So you have to assemble the value yourself:ADCSRA=(1<<ADEN)|(1<<ADSC)|(1<<ADIE)|(1<<ADFR)|6;It is not as nice to read, but is will be compiled to a single instruction word.It is hard to decide. For registers I prefer the AVR solution, for IO pins or other settings where I only want to change a single bit the microchip way is much nicer because you can write _LATB1=1; instead of PORTB|=(1<<PB1);

author: Daving
author_rank: Contributor
timestamp: January 27, 2016, 08:39:30 pm
content: Quote from: Daving on January 25, 2016, 06:43:14 pm1.36 is out, now.

author: Daving
author_rank: Contributor
timestamp: January 28, 2016, 07:04:31 am
content: Quote from: bktemp on January 27, 2016, 03:38:54 pmThe same type of definitions are defined in the xc.h headers. Not many use them, though.What I've done in the past is something like this:// In some utility header, included in ADC c file.#define UTIL_Mask(bits) ((1 << ((bits)+1)) - 1)// In ADC c file. Not needed by USER API.#define ADC_ADFM_POS (3)#define ADC_ADFM_BITS (1)#define ADC_Adfm(a) ((UTIL_Mask(ADC_ADFM_BITS) & (a)) << ADC_ADFM_POS)#define ADC_ADFM_LEFT (ADC_Adfm(0))#define ADC_ADFM_RIGHT (ADC_Adfm(1))Then I can OR ( | ) the settings together.ADC1CON = (ADC_ADFM_RIGHT | ADC_ADCS_FOSC_32 | ADC_ADPREF_VDD)For 32 bit registers, this could get unweildy, so if the compiler optimizes right, you should be able to do this.uint32_t config = ADC_ADFM_RIGHT;config |= ADC_ADCS_FOSC_32;config |= ADC_ADPREF_VDD;ADC1CON = config;...config = blah;config |= foo;config |= bar;ADC2CON = config;The compiler could realize it's a local variable that only gets copied to the SFR once and never takes inputs from anything but literals. Depends on the compiler and options, I suppose.

author: westfw
author_rank: Super Contributor
timestamp: January 28, 2016, 08:31:39 am
content: QuoteGiven reasonably sensible typedefs (eg CMSIS) you can also define local/register variables of the same type as the peripheral register, manipulate the bits "elegantly" and then assign them to the actual peripheral register "in bulk." Here's an actual example, from Atmel ASF code for SAMD:Code:SYSCTRL_OSC8M_Type temp = SYSCTRL->OSC8M;/* Use temporary struct to reduce register access */temp.bit.PRESC = config->prescaler;temp.bit.ONDEMAND = config->on_demand;temp.bit.RUNSTDBY = config->run_in_standby;SYSCTRL->OSC8M = temp;

author: bktemp
author_rank: Super Contributor
timestamp: January 28, 2016, 08:37:00 am
content: Quote from: Daving on January 28, 2016, 07:04:31 amMost likely because they have added them recently and most people do not know about it (like me). When I started with dsPICs/PIC24 only the bitfields were available in the C30 header files.Good to know, this will make most init codes much smaller.The names are quite long (having the format registername_bitname_POSITION), so you either get a long line or have to split it into several lines like you did. Your solution is probably the best and every reasonable compiler should assemble the bits into a single 8/16/32bit word.It often takes a long time, but at the end Microchip makes many things right.

author: dannyf
author_rank: Super Contributor
timestamp: January 28, 2016, 12:11:13 pm
content: It is straight forward to cast a struct to a byte and get the bits defined.Has been around since the picc days and can be done with avrs too.I prefer masks personally. I think luminary has an app note that compares the varies approaches to operate on bits and pieces and how effiecint they are.

author: Xenoamor
author_rank: Regular Contributor
timestamp: January 28, 2016, 01:06:52 pm
content: Quote from: dannyf on January 28, 2016, 12:11:13 pmA million times yes. Changing:Code:ADCSRA=(1<<ADEN)|(1<<ADSC)|(1<<ADIE)|(1<<ADFR)|6;to:Code:ADEN = 1;ADSC = 1;ADIE = 1;ADFR = 1Makes working across multiple control registers a lot simpler.

author: Daving
author_rank: Contributor
timestamp: January 28, 2016, 04:53:41 pm
content: Quote from: Xenoamor on January 28, 2016, 01:06:52 pmThe problem is that this:Code:ADEN = 1;ADSC = 1;ADIE = 1;ADFR = 1;And this:Code:ADSC = 1;ADIE = 1;ADFR = 1;ADEN = 1;Have different behavior in the chip. Especially since in your example, you set the enable bit before anything else.

author: hans
author_rank: Super Contributor
timestamp: January 28, 2016, 06:35:28 pm
content: I prefer bitfields. Code is far more readible. I ran some tests, but posting it is a bit beyond the scope of this thread (I can post my findings in it's own thread if anyone is interested), but I only found very minor variations. I ran a simple timer init sequence and saw only 1-3 instructions difference between 8-bit PIC, 16-bit PIC, 32-bit PIC and Cortex m4 ARM with GCC 4.8 (all with PRO or -O1 optimisations obviously). Winner? Bit masks obviously.. but IMHO the code is less readable.Yes you need to watch out those order of execution. The biggest pain on 32-bit CPUs is they generate a lot of code for 1 RMW. Many 8 and 16-bit CPUs can perform AND/OR directly on I/O, like PIC24 has: AND f, WREG -> store in WREG. Or bitset/clr. If you first need to disable a peripheral, then change bits around, and then re-enable it.. you can see a big difference between 2 platforms.If you do want to bit-bang directly, I recommended working on a local variable first (e.g. to clear some bits of a field in order to write a new value to it). This variable does not have to be volatile. This has the advantage of the compiler being able to be very aggressive and generating exactly the same or even more efficient code than bitfields.

author: captbill
author_rank: Contributor
timestamp: February 02, 2016, 06:26:30 pm
content: Here's a novel idea:Take a look at PICL which is a compiler for the PIC16Cxx written in Oberon. The whole compiler is written in <800 lines of code and that includes the uploader/flasher as well. Heck, you could quite possibly study 5 pages of code and roll up your sleeves and fix or implement whatever you might need with less hassle than mucking with these overly complicated C compilers.https://www.inf.ethz.ch/personal/wirth/PICL/index.htmlHow about this for a days lab assignment:https://www.inf.ethz.ch/personal/wirth/PICL/PIC.pdf