STM uC Vs Microchip uC - Page 1
Forum section: electronics / general

author: hamdi.tn
author_rank: Frequent Contributor
timestamp: August 03, 2014, 01:33:10 pm
content: Hi everyone,i been using microchip for a long time , all family included, most of my project didn't much of processing so 18F family is what i used most. A year ago i started using STM32F0 and god how frustrating that thing isi was likethe thing need thousand line to set the input/output configuration only And i had a hard time to understand how to manually program every register and get clear idea how this think really work from a low level electronic point of view and not with all that C++ fashion programming crap, So i drop it, and after doing one project with it i forgot about it. Now i have more to do with STM32 again. i thought why not ask everyone here what they think about it, since am not really objective concerning those STM µC.

author: AndyC_772
author_rank: Super Contributor
timestamp: August 03, 2014, 01:52:03 pm
content: Have a read if you've not done so already:https://www.eevblog.com/forum/microcontrollers/stm32f4xx-hal-drivers/

author: dannyf
author_rank: Super Contributor
timestamp: August 03, 2014, 02:45:11 pm
content: Your experience is not atypical, nor unexpected.A more complex chip means more things to configure, which in turn means more complexity for the programmer.That's not to say that such complexity cannot be managed, through good programming practices.For example, the following sets out a pin to output and then set / clear it.Code:#include <gpio.h> //our gpio related routines#define LED_PORT GPIOA#define LED_DDR GPIOA#define LED ((1<<2) | (1<<3)) //led on pin2 and pin3PIN_OUT(LED_DDR, LED); //set led as outputPIN_SET(LED_PORT, LED); //set ledPIN_CLR(LED_PORT, LED); //clear ledFor me, I can compile that piece of code, unmodified, on PIC, AVR, STM8, various flavors of ARM and it will produce identical behaviors. All I need to do is to link in the right gpio.h/.c files.The same principle applies to other peripherals - if you structure your code right and write code with some pre-planning, you will accumulate a large body of code that can greatly reduce your difficulties in porting and implementing code on different mcus.

author: AndyC_772
author_rank: Super Contributor
timestamp: August 03, 2014, 03:37:13 pm
content: It's probably also fair to point out that GPIO access is something which is particularly easy on a PIC, and particularly difficult by comparison on an STM32 if you're using ST's libraries. Don't let that put you off; once you've written your code to initialise the hardware, and you have your own function to set or clear I/O pins, then your application development will start to become much more familiar again.Don't be afraid to ignore ST's libraries and just go ahead and write to BSRR. It's quite liberating.

author: hamdi.tn
author_rank: Frequent Contributor
timestamp: August 03, 2014, 04:29:31 pm
content: thanks,@andy i just read what you wrote on the other post it's almost the same experience, i started to make a progress when i wrote directly to concerned register and not through supplied function.I used Cube for schematics, when i generated the code same thing those HAL function are not compatible with IDE library am using (IAR) and again to trash i wrote my own code.I share every single opinion you wrote there, concerning lack of documentation and how much supplied function and tools areefficient."I'll address the issue of portability between families if and when it becomes an issue, which I strongly suspect will be "never"."My target uC is a F1 device but for now am using an F0 to test functionality of my prototype ( waiting for the F1 chip to be delivered ) if i understand your sentence right , i will have no issue of portability between both device. So my code can be almost the same. Did you make same test with different family ?i think the answer to my question is there is no easy way to do it, i will eventually chose to either write directly registers or use the supplied function according to my project needs.@dannyfi like the way you wrote that example however it does not solve the main problem, of going through the configuration of all those registers and what is the best way to do it, your gpio file will be filled with those infinite line just to tell the damn compiler you need PA0 to be an outputi will remember this method when i write a code that need to be portable on many uCSo in general, since many ppl here had experience with multiple type of uC, when choosing a specific uC what family you prefer by putting in mind processing capability , cost , and time to market.

author: dannyf
author_rank: Super Contributor
timestamp: August 03, 2014, 04:50:57 pm
content: QuoteYou didn't get the approach. It is about hiding the details away from the user so that the user application is equally "simple" as in the 8-bit world.QuoteThat depends on your toolchain, your chip and more importantly your approach.For example, the PIN_SET() implementation can be as simple as this:Code:#define PIN_SET(gpio, pins) gpio->BSRR |= (pins)or this:Code:#define PIN_SET(port, pins)port->ODR |= (pins)or this:Code:#define PIN_SET(port, pins)MAP_GPIOPinWrite(port, (pins), (pins))or this:Code:#define PIN_SET(port, pins)HWREG(port + (GPIO_O_DATA + ((pins) << 2))) = (pins)or this:Code:#define PIN_SET(port, bits)port |= (bits)//set bits on portor any other implementation on your toolchain and for your chip.But that's irrelevant, as long as you can achieve the goal of simplifying coding in the user space.The issue you are encountering isn't unique to ST chips, or even ARM. It is fundamentally caused by the powerfulness of the chips. You just need to come up with a way to manage it in a way that is acceptable to you.

author: nctnico
author_rank: Super Contributor
timestamp: August 03, 2014, 04:54:28 pm
content: Quote from: hamdi.tn on August 03, 2014, 01:33:10 pmLook at the ARM devices from NXP. Simple to use and they keep the same peripherals in future versions.

author: andyturk
author_rank: Frequent Contributor
timestamp: August 03, 2014, 09:48:29 pm
content: Quote from: hamdi.tn on August 03, 2014, 04:29:31 pmAre you talking about how to initialize all the GPIO ports after reset? Here's how I do it:pins.h:Code:#pragma once#include "stm32f4xx.h"#include <cstdint>#define ALL_PORTS \PORT(A) \PORT(B) \PORT(C) \PORT(D) \PORT(E) \PORT(F) \PORT(G) \PORT(H) \PORT(I)/** The ALL_PINS macro, defined below, contains the I/O pin architecture-* specific GPIO configuration for the application.** port: GPIOA .. GPIOI* pin: 0 .. 15* name: any identifier* mode: IN | OUT | AN "analog" | AF "alternate function"* type: PP "push pull" | OD "open drain"* pupdr: NOPULL | UP | DOWN* odr: 0 | 1* af: 0 .. 15*/// port, pin, name, mode, type, speed, pupdr, odr, af#define ALL_PINS \PIN(GPIOA, 1, DBG_EN, OUT, PP, Low, NOPULL, 0, NONE) \PIN(GPIOA, 2, FLASH_HOLD, OUT, PP, High, NOPULL, 1, NONE) \PIN(GPIOA, 3, FLASH_WP, OUT, PP, High, NOPULL, 1, NONE) \PIN(GPIOA, 4, SPI1_CS, OUT, PP, High, NOPULL, 1, NONE) \PIN(GPIOA, 5, SPI1_SCK, AF, PP, High, NOPULL, 0, SPI1) \PIN(GPIOA, 6, SPI1_MISO, AF, PP, High, NOPULL, 0, SPI1) \PIN(GPIOA, 7, SPI1_MOSI, AF, PP, High, NOPULL, 0, SPI1) \PIN(GPIOA, 9, USB_VBUS, IN, PP, Low, NOPULL, 0, NONE) \PIN(GPIOA, 11, USB_N, AF, PP, Low, NOPULL, 0, OTG_FS) \PIN(GPIOA, 12, USB_P, AF, PP, Low, NOPULL, 0, OTG_FS) \PIN(GPIOA, 13, SWDIO, AF, PP, High, NOPULL, 0, SWJ) \PIN(GPIOA, 14, SWCLK, AF, PP, High, NOPULL, 0, SWJ) \\PIN(GPIOB, 0, DISP_RES, OUT, PP, High, NOPULL, 0, NONE) \PIN(GPIOB, 1, DISP_CS, OUT, PP, High, NOPULL, 1, NONE) \PIN(GPIOB, 2, BOOT1, IN, PP, Low, NOPULL, 0, NONE) \PIN(GPIOB, 3, DISP_SCK, AF, PP, High, NOPULL, 0, SPI3) \PIN(GPIOB, 4, DISP_DC, OUT, PP, High, NOPULL, 0, NONE) \PIN(GPIOB, 5, DISP_MOSI, AF, PP, High, NOPULL, 0, SPI3) \PIN(GPIOB, 10, DBG_TDI, IN, PP, High, NOPULL, 0, NONE) \PIN(GPIOB, 11, DBG_TRST, IN, PP, High, NOPULL, 0, NONE) \PIN(GPIOB, 12, DBG_SWDIO, IN, PP, High, NOPULL, 0, NONE) \PIN(GPIOB, 13, DBG_SWCLK, IN, PP, High, NOPULL, 0, NONE) \PIN(GPIOB, 14, DBG_SWO, IN, PP, High, NOPULL, 0, NONE) \PIN(GPIOB, 15, DBG_NRST, IN, PP, High, NOPULL, 0, NONE) \\PIN(GPIOC, 0, SW3, IN, PP, Low, UP, 0, NONE) \PIN(GPIOC, 1, SW4, IN, PP, Low, UP, 0, NONE) \PIN(GPIOC, 2, VCC_SENSE, AN, PP, Low, NOPULL, 0, NONE) \PIN(GPIOC, 3, SW5, IN, PP, Low, UP, 0, NONE) \PIN(GPIOC, 7, EN_VCC_USB, OUT, PP, High, NOPULL, 1, NONE) \PIN(GPIOC, 8, EN_VCC_3V3, OUT, PP, High, NOPULL, 1, NONE) \PIN(GPIOC, 9, LED1, OUT, PP, High, NOPULL, 0, NONE) \PIN(GPIOC, 10, DBG_TX, IN, PP, High, NOPULL, 0, NONE) \PIN(GPIOC, 11, DBG_RX, IN, PP, High, NOPULL, 0, NONE) \PIN(GPIOC, 13, LED2, OUT, PP, High, NOPULL, 1, NONE) \enum all_pins_defs {#define PIN(port,pin,name,mode,ppod,speed,pull,value,altfn) name = pin,ALL_PINS#undef PIN};pins.cc:Code:#include "pins.h"#include "stm32f4xx.h"#include <cstdint>struct pin_config_t {uint32_t periph;GPIO_TypeDef *port;GPIO_InitTypeDef init;uint8_t alternate_fn;BitAction odr;};enum {GPIO_AF_NONE = 0xff};static const pin_config_t pin_config[] = {#define PIN(port,pin,name,mode,ppod,speed,pull,value,altfn) \{RCC_AHB1Periph_ ## port, port, {1 << (pin), GPIO_Mode_ ## mode, GPIO_ ## speed ## _Speed, GPIO_OType_ ## ppod, GPIO_PuPd_ ## pull}, GPIO_AF_ ## altfn, (BitAction) value },ALL_PINS#undef PIN};void configure_gpio_pins() {GPIO_InitTypeDef unused;// fill in ST's idea of a default pin// Note: this may not be correct for lowest power consumptionGPIO_StructInit(&unused);// Call GPIO_Init() to initialize each port#define PORT(name) GPIO_Init(GPIO ## name, &unused);ALL_PORTS#undef PORTfor(unsigned i=0; i < sizeof(pin_config)/sizeof(pin_config_t); ++i) {const pin_config_t &config(pin_config);// enable the port for the pin. OK to do this more than once.RCC_AHB1PeriphClockCmd(config.periph, ENABLE);// initialize the pinGPIO_Init(config.port, (GPIO_InitTypeDef *) &config.init);// set the altfnif (config.alternate_fn != GPIO_AF_NONE) {GPIO_PinAFConfig(config.port, config.init.GPIO_Pin, config.alternate_fn);}if (config.init.GPIO_Mode == GPIO_Mode_OUT) {GPIO_WriteBit(config.port, config.init.GPIO_Pin, config.odr);}}}

author: hamdi.tn
author_rank: Frequent Contributor
timestamp: August 03, 2014, 10:22:12 pm
content: @dannyf , thank for explaining i get your approach now, total agree.Quote from: nctnico on August 03, 2014, 04:54:28 pmi will at first possible occasion@andyturki will certainty try this code, it's not the "how to" that am asking about really, i just put the gpio as an example of how i find programming STM32 long and annoying, i wanted to see how other developer feel about it, and if anyone have a better approach than the one i use.the thing is am more in electronic than in coding, i do software certainly for ages, i will not claim that my code is perfect it may look like shit for a trained IT engineer eyes but it workwhen code is much oriented for ppl that are familiar with C++ developer and such it kind of bores me, and in a way this is what happening here. for the same reason i agree with AndyC about writing your own function that address BSRR directly.

author: andyturk
author_rank: Frequent Contributor
timestamp: August 03, 2014, 10:38:13 pm
content: Quote from: hamdi.tn on August 03, 2014, 10:22:12 pmWell, I come from an "IT" background and most of the firmware I've seen written in C horrible, so it's not just you! :-) The stuff you get from OEMs is especially bad with code that's clearly a copy-and-paste from somewhere else, uses #defines rather than more modern constructs, is chocked full of global variables and generally looks like it was written by underpaid interns in the mid 90s. Blech.</rant>Hitting BSRR directly is just fine. I like to do that in a C++ template, but an inline function will work too and helps hide the details without adding any overhead.

author: dannyf
author_rank: Super Contributor
timestamp: August 04, 2014, 12:43:10 am
content: QuoteThe approach is really to "box it": put the respective functions into layers so that invocation for such functions is as simple and intuitive as on an 8-bit machine. The fact that the mcu has to go through many lines / instructions to do get it done is not as critical from the programmer's perspective, for most applications.

author: nctnico
author_rank: Super Contributor
timestamp: August 04, 2014, 10:54:00 am
content: Just adding layers (boxing stuff) doesn't make a program more readable. Actually it makes it harder to maintain because the next programmer must read through all the layers to find out what the program actually does in case something needs to be changed or fixed.If I add a layer in a piece of software I ask myself: does this 'layer' add functionality to the program? If the answer is NO (the layer just moves data around) then I leave it out. It often means that the layers above (application) and below (hardware control) need more work to make them more compatible which eachother.

author: Kjelt
author_rank: Super Contributor
timestamp: August 04, 2014, 11:03:30 am
content: All depends on what you call a layer. I think you would hardly disagree that a HAL is neccesary.The nice thing about layering is that the programmer in case of changes/problems does not have to be bothered by the lower (tested) layers and can concentrate on the stuff above.

author: bwat
author_rank: Frequent Contributor
timestamp: August 04, 2014, 11:57:38 am
content: Quote from: nctnico on August 04, 2014, 10:54:00 amIt's something that's happening many times between transistor and your high-level language code. Of course it can be done badly, but when done by someone who understands the machine and macros you get something useful. When done by someone who understands the machine and language design, you get something really useful.

author: amyk
author_rank: Super Contributor
timestamp: August 04, 2014, 12:35:19 pm
content: Quote from: Kjelt on August 04, 2014, 11:03:30 amIn theory, yes.In practice... not really.

author: bwat
author_rank: Frequent Contributor
timestamp: August 04, 2014, 01:10:37 pm
content: Quote from: amyk on August 04, 2014, 12:35:19 pmThen maybe you should be looking at your practice because this is all we've gotWith regards to hardware design, I can't remember the last time something had been abstracted and tested then went on to fail for me and this failure wasn't down to either:i) misuse, orii) it wasn't properly tested. (copy/paste error in the ALU circuit for an AND operation so bit N of an operand was used instead of bit M (M=/=N) and my insufficient tests missed it).As far as software is concerned, again I can't remember the last time something broke that had been deemed working. A good chunk my design involves the writing of proofs by induction or equational reasoning.There is a large class of systems that are working 24 hours a day, 7 days week. They are so reliable we don't even think expect failure just like we always expect water out of the tap and electricity from the socket. It can be done.

author: nctnico
author_rank: Super Contributor
timestamp: August 04, 2014, 01:59:35 pm
content: Quote from: bwat on August 04, 2014, 01:10:37 pmThese are minor issues. The biggest problem usually is proper documentation. Without documentation it is much easier to analyse what 2 layers of abstraction are actually supposed to do than to analyse 10 layers of abstration where a lot of layers don't really add anything to the software. Also: with proper documentation it becomes easier to re-use software and less layers means less work on documentation.

author: tszaboo
author_rank: Super Contributor
timestamp: August 04, 2014, 02:10:56 pm
content: The problem is obvious. You changed the architecture of the hardware, without changing how you write code. If you take 20 years advance there, you should advance here also. I mean ARM is not meant to be programmed with magic numbers to registers. It has CMSIS, and a help file, which is the first place to look at, if you need to configure something. Help file, not the datasheet.I agree that setting up the develpoment tools is much harder with ARM, and the learning curve is much steeper, but I suspect that it will wash away every 8 bit development in the very near future.

author: nctnico
author_rank: Super Contributor
timestamp: August 04, 2014, 02:39:12 pm
content: SighThere are two kinds of peripherals on an ARM controller:1) The simples ones (UART, SPI, timers) where using a library is total overkill and not worth it because of the numerous ways a peripheral can be used.2) The complex ones (ethernet, USB) where using a library is mandatory and easy because the number of uses for such peripherals is very limited.Just pouring software layers on top of hardware is like pouring Sate sauce over all your food hoping it tastes better.The simple peripherals have not changed much between ancient 8 bit controllers and ARM controllers. They don't have to. The basics of I/O pins, UART, SPI, timers, I2C, etc have been the same for over 30 years. Why try to make programming these hard to do? Like you have to be a software engineer to work with ARM? I'm almost starting to get the feeling some people feel they belong to some elitist group who know how to program ARM controllers and try to keep others out by spreading nonsense about how hard ARM controllers are to work with.

author: hamdi.tn
author_rank: Frequent Contributor
timestamp: August 04, 2014, 02:57:23 pm
content: @nctnico, can't explain what i need to say better than what you did, why i feel the need that i have to be a software engineer to make it work.Quote from: nctnico on August 04, 2014, 02:39:12 pmI tried to get a job as a firmware developer once in some big developing firm specialized in EE ( so they say), my application was automatically disqualified, they ONLY accept ppl from a local elite IT university here... now i can see why

author: AndyC_772
author_rank: Super Contributor
timestamp: August 04, 2014, 04:19:13 pm
content: Quote from: NANDBlog on August 04, 2014, 02:10:56 pmSorry, can't agree with this at all.From my experience with trying to develop a new application on an STM32 a couple of weeks ago, two things became painfully obvious:- despite the fact that it's apparently frowned upon in some circles, poking hardware registers to drive the standard peripherals such as timers and UARTs was by far the clearest, fastest and most space efficient way to do it. Allowing for the fact the peripherals themselves are more complex and capable than their counterparts in 8-bit micros, accessing them directly is really no more difficult. If you don't want to use the extra features, set the bits that control those features to zero.- by complete contrast, trying to work out what the ST library functions were actually doing (and not doing!), and which function calls are actually needed to configure and use a device in a particular way, was a pain. Adding a layer of poorly documented obfuscation is absolutely NOT a way to make code easier to write, read, or port across platforms.

author: bwat
author_rank: Frequent Contributor
timestamp: August 04, 2014, 04:48:33 pm
content: Quote from: hamdi.tn on August 04, 2014, 02:57:23 pmA couple of points:1) You may have dodged a bullet not getting that job.2) It seems like you're an EE struggling with complexity with regards to software design. Just so you know, everybody struggles with complexity in software design. It takes a lot of time building a system with a good structure.

author: bwat
author_rank: Frequent Contributor
timestamp: August 04, 2014, 05:06:59 pm
content: Quote from: nctnico on August 04, 2014, 01:59:35 pmIf you're analysing abstractions then it's probably the case that they were not meant for you.

author: nctnico
author_rank: Super Contributor
timestamp: August 04, 2014, 05:17:49 pm
content: If analysing the source of a poorly documented non-working library (=abstraction layer) is the wrong way to move ahead then I'm very curious about your approach in such a situation.

author: bwat
author_rank: Frequent Contributor
timestamp: August 04, 2014, 05:41:07 pm
content: Quote from: nctnico on August 04, 2014, 05:17:49 pmI'll repeat in slightly different terms but with the same meaning: you shouldn't need to look at the internals of an abstraction. In your case your abstraction doesn't work - something that 99% of the time could be determined without looking at the internals - so drop it and find something that does or create your own.Also a library by definition is not an abstraction layer. To abstract is to determine those properties of the universe of objects which are essential and those which are nonessential, then identify of those objects that differ only in the nonessential. A layer is a step in a hierarchical design. A library is a collection of abstractions but these need not form a layer.

author: djacobow
author_rank: Super Contributor
timestamp: August 04, 2014, 05:59:19 pm
content: I don't understand the emphasis on "bitness" in this discussion. 8b, 32b, what does it matter? These chips all have CPUs with a bunch of peripherals with registers sitting at memory addresses. The complexity increase, if there is any, is in the number and complexity of the peripherals themselves. Seems to have almost nothing to do with the core.My problem with the ST HAL is that it does a poor job of abstracting anything. To give a minor example, you need to turn on the clocks to various peripherals in order to use them. But the peripherals are spread out on two separate APB busses. So far, so good. I can think of good reasons to do that. But the HAL requires the programmer to know which bus the given peripheral is on, and you have to use a separate call RCC_APB2PeriphClockCmd or RCC_APB1PeriphClockCmd to turn the peripheral on. Moreover, those calls take constants with the peripheral names that are defined as macros. You can assign the wrong peripheral to the wrong function with nary a peep of complaint at compile time.This is a case where ST could have implemented one call, with a proper typed enum and the HAL could have abstracted which clock is getting turned on for the programmer. In fact, with a bit of effort, they could probably have made a nice abstraction to handle ALL the clock configuration on the chip in a programmer-friendly manner.Most of the ST HAL functions also have the flavor of taking a huge struct that corresponds very closely to the registers themselves, and then using that to set up and control stuff for you. OK, but that's also not providing much abstraction, either. It's just sort of half-cooked. It's one thing to abstract away the hardware and provide a SW interface which is more attuned to how the programmer would /use/ the peripheral, it's quite another to just put a layer of gloss on poking.Finally, I want to make a shout-out to the auto-generated boilerplate code put out by some of these configuration tools. There is nothing wrong with this concept, but you have to admit that code is often of low quality, has all the hallmarks of being copied and pasted, usually comes with voluminous "comments" that don't tell you much of anything, and often has the full monty of register configuration when, for a given task, only a few things are important. This makes such code a pretty crappy learning tool, which is a shame, since it seems to be the main way to learn how ST parts work -- more popular than the docs.ALL THAT SAID, they're nice chips, they do all sorts of cool stuff and for cheap, and it's not like you can't make it all work with a little effort. But I think it's weird to say that "this is the price of complexity, so deal with it." Complexity is the sh*ts, but that does not mean there cannot be better and worse ways of supporting it.

author: AndyC_772
author_rank: Super Contributor
timestamp: August 04, 2014, 06:00:56 pm
content: Quote from: bwat on August 04, 2014, 05:41:07 pmThat sounds like the sort of quote I'd expect to see associated with something like, say, a broken down moon rover, or perhaps a nuclear incident.Peering inside a library function isn't just about checking it's correctly implemented; it's a perfectly valid and necessary way to find out exactly what it's doing, what it's NOT doing, and how to use it.It might be nice indeed if there were a definitively accurate manual available, which would describe it in detail with plenty of clear examples and explanatory notes, but even if there were, such a manual would probably be less concise than simply reading the source code.The case of setting up a microcontroller peripheral is a bit of a 'no mans land' when it comes to choosing the best approach, and I stand by my assertion that poking the hardware directly is often the best approach.The end result - whether a peripheral is accessed directly or via a hardware abstraction layer - is a set of bit patterns being written to registers, and the exact, specific details of those bits probably are important to the end application. We need to be able to, for example, set up timer 1 in compare mode with a clock source X, prescaler Y, and generate an interrupt of priority P when the timer reaches value Z for the N'th time. All very, very specific, with little or no room for interpretation.It's not like, say, a graphics library, where I might know I want to draw a triangle with known vertices, but not how the underlying hardware works. In that case I'd completely agree that digging into the library looking for register writes to the GPU is probably unhelpful.

author: bwat
author_rank: Frequent Contributor
timestamp: August 04, 2014, 06:28:02 pm
content: Quote from: AndyC_772 on August 04, 2014, 06:00:56 pmOr a CPU, or a compiler, or a .... You're quite happily using a whole host of abstractions in your daily work and you bother yourself not a jot how they're implemented.Quote from: AndyC_772 on August 04, 2014, 06:00:56 pmIf it is necessary then there is a problem. I honestly cannot think of one single abstraction where it is necessary. I can use the "read" and "write" calls provided by my OS without looking at the source code or these functions. I can even have the very same machine boot an OS of my creating without understanding the boot process or seeing the source code for BIOS int 13h, function 02h, "Read Sector".When is it evernecessary? If you have to concern yourself with the thing that was abstracted then the abstraction isn't for you.Quote from: AndyC_772 on August 04, 2014, 06:00:56 pmA manual less concise? The last manual I wrote was 381 pages for a system that comprised roughly 55000 lines of code. I've never seen a manual less concise than the source code.Quote from: AndyC_772 on August 04, 2014, 06:00:56 pmIn this case the abstraction isn't for you. Just to be clear, I'm not forcing abstractions on people, I'm just saying that if you need to look inside an abstraction, then eitheri) you're the designer of the abstraction, orii) the abstraction wasn't designed for you, so use your own or find another.

author: andyturk
author_rank: Frequent Contributor
timestamp: August 04, 2014, 07:16:30 pm
content: Quote from: bwat on August 04, 2014, 06:28:02 pmIt seems like most of the times I've had to crack the seal on one of these abstractions is when something doesn't work right. E.g., an I2C slave implementation isn't working right and I have to figure out why. The library may be implemented correctly in the mind of it's author, but maybe it's susceptible to other problems in the system and the only way to figure that out is a deep dive into some gnarly interrupt code. That I2C library is aLeaky Abstraction.Libraries (and abstractions in general) are nice, but if they leak too much and you're constantly having to open up the box to see what's inside, then the box isn't helping much. Just take the stuff out and throw the box away.PS. ALUs are *not* leaky abstractions.PPS. ... unless you care about overflow, saturating arithmetic, etc.

author: westfw
author_rank: Super Contributor
timestamp: August 04, 2014, 08:04:24 pm
content: QuoteThe problem is that on a lot of ARM chips, even the "simple" peripherals are quite complex compared to what people are used to on an 8bit chip. For example, an 8bit GPIO port on a TI Tiva controller is controlled by about 280 registers.Compared to the three that you're used to using on a PIC or AVR (in, out, direction!), that's a bit of a shock. And it doesn't include bit-banding, or that the ARM registers are 32bits and sometimes use all 32.Now, some of that is because things that were defaults on your 8bit controller now have to be done explicitly (enabling the clock for the peripheral circuitry, for example.) And some are things that were documented elsewhere and don't show up as readily in 8bit microcontrollers (explicit setting of those pins to be connected to the GPIO peripheral. Pin change interrupts.) And some of it is because of the things that have been done to get safe/efficient IO bit-banging out of a load/store RISC architecture.So you think "I should just use the libraries they provide instead; that will be easier." But there are 40+ functions involved, and they're not very well documented ("When do I use GPIOPinTypeGPIOOutput(GPIO_PORTA_BASE, GPIO_PIN_1), and when do I use GPIOPinConfigure(GPIO_PA1_something)?") And that the abstraction is weird. And the code is big and/or slow. And you start thinking "I bought this 32k ARM chip as an 8bit replacement, figuring that the architecture improvements would sort-of even out against the complexity increase, but it just took me 100 bytes to set up pins in a way that only took 10 bytes on my 8bit..."(And then you look at the Atmel ARM chips instead and discover that their implementation of GPIO is quite different. Sigh.)

author: Kjelt
author_rank: Super Contributor
timestamp: August 04, 2014, 08:10:21 pm
content: Quote from: andyturk on August 04, 2014, 07:16:30 pmSo where do you draw the line? Now it is a C library written for a peripheral by some SW engineers working for the firm that build the peripheral, next it is the assembler generated by the compiler, next it is the vhdl used for generating the hardware peripheral itself (which also is buggy hence the errata sheets for microcontrollers) and finally we have the physical silicon which might have an inpurity.The whole datasheet is an abstraction of the physical reality and can have bugs ! Maybe you are implementing your software on buggy documents, or buggy hardware that need to be "opened up"To give a real life example, the I2C peripheral of the STM8 and STM32 is a bit wanky (read the errata sheet) so ST got complaints from customers that their implementations were sometimes having problems. Good, ST spends a lot of money making an as good as possible (CPAL) implementation for the darn peripheral.I bet that any of your implementations for this peripheral from scratch are buggy compared to the CPAL implementation that handles almost all (never 100%) of those quircks the peripheral has. We had in our company a lot of engineers frustrated by this peripheral before we got the CPAL implementation. Yeah it is not perfect and probably in some cases can be tweaked and optimized a bit further but hell if you want or have to write that damn thing from scratch yourself.

author: nctnico
author_rank: Super Contributor
timestamp: August 04, 2014, 08:20:20 pm
content: Quote from: westfw on August 04, 2014, 08:04:24 pmYou guys make me happier about choosing for ARM controllers from NXP every day! O0

author: djacobow
author_rank: Super Contributor
timestamp: August 04, 2014, 08:38:03 pm
content: Quote from: westfw on August 04, 2014, 08:04:24 pmI think this perhaps starts to get at one of the "issues" here, namely that some of these software abstractions Just Don't Work, and perhaps they cannot be made to work. It's not like you can merrily go along your software way without become intricately familiar with how your chip actually works. IO is perhaps the poster-child for this.Have you ever laid out a board only to find out that your plans for Pin $x were not compatible with the chip because you forgot to account for: peripheral attachable/not attachable to it, limitation or some other incompatible resource conflict with the particular "instance" of the peripheral you wanted to use, or special pin-specific limited drive strength, or no programmable pullup/pulldown/open collector on that pin, or it turns out to be one of n non-5V-tolerant pins in a sea of dozens that are? I certainly have. Am I the only one? Sure, it's my mistake; it was all in the docs. But sometimes you miss things.Which is to say maybe you can never cleanly abstract IO, at least not the way it is currently done. One /could/ design a chip where every pin is completely mappable to every peripheral through a complete switch matrix. That's certainly easy enough to abstract. But alas, at best it requires more on-chip area for that circuitry and at worst, high speed peripherals probably need to be "somewhat near" the pads they drive and so it cannot even work that way. (It can take multiple clock cycles to get from one end to the other of a high clock freq chip.) And you'll always be left with some peripherals that need special pads with special properties, etc.So, you sort of end up back with just wanting to poke under the hood and see how the damn thing works.-- dave jPS -- 280 registers for one set of IO pints? Wow. I can't even imagine what they do: mux some peripherals, set drive strengths and pullups, mask interrupts or setup interrupt routing ... ok, I'm out of ideas and I don't think I hit 280 x 32b . :-)

author: Kjelt
author_rank: Super Contributor
timestamp: August 04, 2014, 08:40:54 pm
content: Quote from: nctnico on August 04, 2014, 08:20:20 pmNXP also has errata sheets with very bad bugs in the hardware, peripherals that hang on some cases etc. ES_LPC177x/8x.pdfI think there is no microcontroller hardware without faults just as there is no software without bugs

author: nctnico
author_rank: Super Contributor
timestamp: August 04, 2014, 09:09:35 pm
content: Quote from: Kjelt on August 04, 2014, 08:40:54 pmTrue but really severe bugs in NXP ARMs controllers are very rare and often fixed in the next silicon revision. The mainstream series controllers have 3 or 4 minor bugs which are easy to work around IF they even cause a potential problem in a particular project.

author: dannyf
author_rank: Super Contributor
timestamp: August 04, 2014, 10:00:43 pm
content: -The simple peripherals have not changed much between ancient 8 bit controllers and ARM controllers. They don't have to. The basics-there is a way to settle this: why don't you show us a complete project that sends a char over spi and at the same time receives it in the isr, using just register access on any of those stm32 chips?that way, we can learn from a master programmer like you. I have also purposefully made the assignment so simple that even a caveman can do it so you will never fail. Win win for every one.ready, set and go.I look forward to seeing your master piece of code. So please don't chicken out on us.

author: dannyf
author_rank: Super Contributor
timestamp: August 04, 2014, 10:05:46 pm
content: -Moreover, those calls take constants with the peripheral names that are defined as macros-with asserts on, you wouldn't be able to compile if there is a mismatch.plus, with a modern ide, it is a simple hovering the mouse over to find out which goes with which.

author: dannyf
author_rank: Super Contributor
timestamp: August 04, 2014, 10:07:23 pm
content: -

author: dannyf
author_rank: Super Contributor
timestamp: August 04, 2014, 10:09:46 pm
content: -I2C peripheral of the STM8 and STM32 is a bit wanky (read-that person had no clue about this when I mentioned it a while back

author: dannyf
author_rank: Super Contributor
timestamp: August 04, 2014, 10:11:20 pm
content: -People actually use those Tiva's? More-many, especially if you count those luminary chips.

author: nctnico
author_rank: Super Contributor
timestamp: August 04, 2014, 10:52:17 pm
content: Quote from: dannyf on August 04, 2014, 10:00:43 pmI'm not using STM32 chips so no go this time. I evaluated the ARM chips from ST a long time ago and found out the peripherals where so bad and obfustigated that mediocre is a huge overstatement. I'm actually amazed people actually put up with them just to save a few pennies per chip. No wonder people find ARM controllers hard. But that is not the problem with ARM controller in general; the problem is in choosing a vendor which uses obfustigated peripherals. So next time spend $30 on an NXP LPCExpresso board instead of $5 on some piece of crap from ST or TI.On the NXP ARM controllers I use setting an I/O pin is a simple matter of setting a bit in a memory address. No more complicated or different than on an 8 bit PIC or MSP430. Same goes for the other peripherals.

author: dannyf
author_rank: Super Contributor
timestamp: August 04, 2014, 11:58:41 pm
content: QuoteOK, I will make that hurdle even lower for: do the same but with whatever ARM chip you are comfortable with.So, when can we expect your finished project?

author: nctnico
author_rank: Super Contributor
timestamp: August 05, 2014, 12:27:17 am
content: Quote from: dannyf on August 04, 2014, 11:58:41 pmI already did that many years ago for a DSP application using the SPI port in SSP mode on an LPC2103:Code:void codec_init(){install_irq(SPI1_INT, codec_handler);//SSP interface setupSSPCR0= 0xf | (1<<4);//16 bits per word, SSI modeSSPIMSC = (1 << 2);//RX interrupt onSSPCR1= (1<<1) | (1<<2);//SSP in slave mode, enabled//setup pinsPINSEL0|= (2<<24) | (2<<28);//P0.12 PCOD_MCLK on MAT1.0//P0.14 COD_SCLK on SCK1PINSEL1|= (1 << 6) | (1<<8) | (1<<10);//P0.19 PCOD_DIN op MISO1//P0.20 COD_DOUT on MOSI1//P0.21 COD_FS on SSEL1}void codec_handler(void){//Codec interrupt handler. Trigger is set at half the FIFO so multiple samples can//be handled inside 1 interruptint in;while((SSPSR & (1<<2))!=0){//read datain=(short) SSPDR;//16 bit 2's complement (=short).if ((in & 1) !=0){//sample from channel1tel_in=in & 0xfffe;}else{//sample from channel2mixer_in=in & 0xfffe;}//write samples to codecSSPDR=(short) mixer_out & 0xfffe;SSPDR=(short) tel_out & 0xfffe;//do processing on samples}}See, it takes 6 lines of code to setup the SPI and interrupt and a couple more inside the interrupt to handle the data.

author: dannyf
author_rank: Super Contributor
timestamp: August 05, 2014, 12:30:21 am
content: Make it a little bit more complete, like a complete project, with main(), etc. so that I can compile it.Remember, I am a newbie here so please help me.

author: nctnico
author_rank: Super Contributor
timestamp: August 05, 2014, 12:43:40 am
content: I leave that as an excersize to the reader. Download the blinky demo from NXP and use CTRL-C/CTRL-V.

author: dannyf
author_rank: Super Contributor
timestamp: August 05, 2014, 12:59:32 am
content: Tough for anyone to try your piece as it has variables undefined in the code piece itself, and no development tool specified.Come on, don't turn in an incomplete assignment. Or we cannot see your greatness.

author: andyturk
author_rank: Frequent Contributor
timestamp: August 05, 2014, 01:41:54 am
content: Quote from: dannyf on August 05, 2014, 12:59:32 amThere was some interesting discussion in this thread, but you're driving people away (again) with this pissing match.

author: westfw
author_rank: Super Contributor
timestamp: August 05, 2014, 03:22:28 am
content: QuoteMost of them (256) implement "bit specific addressing" The low bits of the address are used as a mask to select which bits of the actual output port are actually read or written. This implements atomic bitwise access (for some operations, anyway) of the IO port on an architecture that doesn't normally have any bitwise operators that act on memory. (yes, this is separate from "bit-banding", which allows single bits in most of RAM or IO space to be accessed as if they were complete memory words.)(Both of which are interesting examples of things you can do when you have LOTS of extra address space.)

author: poorchava
author_rank: Super Contributor
timestamp: August 05, 2014, 05:41:37 am
content: STMs are pretty good once you get to know them. Quirkiness of peripherals setup goes away pretty fast, and I generally only use HAL during setup - later those library functions waste too much clock cycles. Those chips are in general quite well engineered and have relatively few bugs (in comparison to some other shit ST had bee selling over the past decade).edit:+there is no non-limited, free (or low cost) toolchains for NXP (aside from general gcc+eclipse approach which is pain in the ass to setup and even moreso for debugging), whereas for ST you can use CooCox and Atmel has their own Atmel Studio.

author: Kjelt
author_rank: Super Contributor
timestamp: August 05, 2014, 06:51:08 am
content: Quote from: nctnico on August 04, 2014, 10:52:17 pmFor starting hobbieist use I can agree with you esp. for some peripherals, most are ok though. For business use, the difference in BOM price (huge numbers) between ST and NXP is significant. I know NRE does also count but in the end few companies calculate those in the costpriceBut getting back on topic, if you had to choose between Microchip or ST which one would you then choose?Only for the Arm core I would still choose the ST.Quote from: poorchava on August 05, 2014, 05:41:37 amThere is CodeRed for LPCXpresso which is free, it now has a 256k limit (last time i checked) which should be more then enough for non-pro use, and pretty good IDE (what I have heard from friends). Only disadvantage is that you need an LPCXpresso board, but these can be get from around $20, even a LPC1769 board costs $20:http://www.embeddedartists.com/products/lpcxpresso/lpc1769_xpr.php

author: tszaboo
author_rank: Super Contributor
timestamp: August 05, 2014, 08:08:13 am
content: Quote from: AndyC_772 on August 04, 2014, 04:19:13 pmAfter you used them for a little more longer, and maybe you have to port it to a different micro, you will agree with me. As I said, one should use the CMSIS, which is made by ARM, not by ST. Now you look like a beginner to electronics, who said that opamps are bad, and too complicated and you prefer transistors... (and now I'm not trying to offend you, just making a point)I really dont understand why would anyone write registers directly, instead of using the library and call standard functions from the c library like printf to send data through the serial port.

author: bwat
author_rank: Frequent Contributor
timestamp: August 05, 2014, 08:37:34 am
content: Quote from: NANDBlog on August 05, 2014, 08:08:13 amHe gave quite a clear motivation for his actions:Quote from: AndyC_772 on August 04, 2014, 04:19:13 pmIt seems you're letting your technical prejudices cloud your thinking.

author: AndyC_772
author_rank: Super Contributor
timestamp: August 05, 2014, 09:07:19 am
content: Calling a standard function like printf achieves a useful objective with less work than the alternative. The parameters I have to supply represent a relatively small amount of design effort compared to the implementation.Calling a library function to, say, set up a timer is completely different. ST's libraries just don't have a simple function that means, say, "generate an interrupt every 10ms, and toggle this GPIO each time", even though the hardware can do it.I have to instead say "Set up timer 3 in compare mode with a clock source X, period Y, output mode Z, interrupts enabled, priority P..." and so on.It's rather like the difference between having a competent junior engineer, and a clueless intern. A competent engineer might be trusted to, say, build a circuit to generate some test signals and monitor a response, and asking that person for help will indeed save time. But ask the intern to do the same, and you'll end up explaining how to hook up all the instruments, switch them on and configure them, all in enough detail that you may as well have done the work yourself - thereby not only saving the time spent explaining things to the intern, but also the risk that they won't actually do what you asked correctly.

author: nctnico
author_rank: Super Contributor
timestamp: August 05, 2014, 09:20:52 am
content: Quote from: Kjelt on August 05, 2014, 06:51:08 amI know you are in the high volume market. From my experience most people work on medium volume products where engineering costs (NRE) are a major part of the cost of a product. I have worked with several people who start by choosing the cheapest parts and then waste hundreds of hours to get something to work which ends up being produced in a series of 100 pieces. There is no other general rule than to look at total costs versus the total production volume to decide whether to look for cheaper components or less development time.@NANDBlog: Your comparison is quite weak because it is unclear whether CMSIS is really portable. After all the peripherals may not be compatible. This limits CMSIS to either being too generic or non portable. I also pointed out that using function pointers makes it impossible to use CMSIS in automotive applications.Let's look at CMSIS versus poking registers. This is how CMSIS works (http://www.keil.com/pack/doc/CMSIS/Driver/html/group__spi__interface__gr.html):Code:SPIdrv->Initialize(mySPI_callback);/* Power up the SPI peripheral */SPIdrv->PowerControl(ARM_POWER_FULL);/* Configure the SPI to Master, 8-bit mode @10000 kBits/sec */SPIdrv->Control(ARM_SPI_MODE_MASTER | ARM_SPI_CPOL1_CPHA1 | ARM_SPI_MSB_LSB | ARM_SPI_SS_MASTER_SW | ARM_SPI_DATA_BITS(8), 10000000);Now the same for poking registers:Code:LPC_SYSCON->SSPCLKDIV=1;LPC_SSP0->CPSR=36; //divider=36 (1MHz clock)LPC_SSP0->CR0=0x7;//8 bitsLPC_SSP0->CR1=(1<<1);Besides that CMSIS seems to assume some kind of threaded operation using interrupts and callback. That is something I don't want in most cases due to other real-time interrupts.

author: dannyf
author_rank: Super Contributor
timestamp: August 05, 2014, 10:39:31 am
content: Again, looks like the master is failing to deliver, even for such a simple example as s/he pointed out. The code piece s/he posted is incomplete and couldn't be compiled -> undefined routines / variables.Not to mention that for the topics being discussed here (peripheral complexity), the LPC210x chips are far closer to a typical 8-bit chips.I am beginning to wonder if the master can actually route the clock to such a simple peripheral on a CMx chip using direct register access,QuoteAs usual, you are mistaken.QuoteCoIDE. Or gcc it utilized.

author: mikerj
author_rank: Super Contributor
timestamp: August 05, 2014, 10:53:43 am
content: Quote from: nctnico on August 04, 2014, 10:52:17 pmI couldn't disagree more. Over the years I have worked with a large number of different microcontrollers, from the original 4 bitters up to the M4 Cortex parts. Every time you move to a new architecture you face a learning curve as you learn the quirks of the device and it's toolchain. The STM32 is not a particularly difficult family to learn at all if you study the reference guides. The biggest single issue as a newbie to this device (IMO) is remembering to enable the clock source for each perhiperal - there have been many hours of head scratching caused by this I suspect.Just as with it's competitors, some of the peripherals are less friendly/more buggy than others, but it's such a (justifiably) popular micro that it's rare you have a problem that someone else hasn't already solved.Quote from: nctnico on August 04, 2014, 10:52:17 pmThis is exactly how you set an I/O pin in an STM32 as well. Why would you think this wasn't the case?Quote from: nctnico on August 05, 2014, 09:20:52 amThat looks like a good argument for using CMSIS right there. The CMSIS code is reasonably self explanatory, anyone with reasonable experience could look at that code and get a good idea of exactly what it is supposed to do. With the LPC example you have a bunch of ambiguously named registers being loaded with magic numbers; a classic example of how it shouldn't be done.Irrespective, you aren't forced to use CMSIS and the STM32 libraries. They are provided to permit compatibility between different vendors, but you can simply program the registers directly with magic numbers if you really think that's the best way to do things.

author: dannyf
author_rank: Super Contributor
timestamp: August 05, 2014, 11:03:30 am
content: QuoteDepending on the NXP ARM chips used and the mode the pins are in, certain ways of setting / clearing them may or may not work.If you want an example of badly designed GPIO module, take a look at the LPC11xx family.

author: paulie
author_rank: Frequent Contributor
timestamp: August 05, 2014, 11:17:38 am
content: Quote from: dannyf on August 05, 2014, 12:30:21 amthat was obvious from your comment in the other thread insisting you can program these chips using only windows hyperterm.

author: nctnico
author_rank: Super Contributor
timestamp: August 05, 2014, 11:38:28 am
content: Quote from: mikerj on August 05, 2014, 10:53:43 amThen why people keep complaining about the GPIO on the STM32 takes 280 registers?QuoteThe registers are not named ambiguously; they match the documentation of the chip. Maybe I should have put //enable as a remark behind the last line for more clarity. I think there are some defines for each bit as well but I never bother to use those. There are only a few bits in each register to configure the SPI interface. Maybe 12 in total including setting the word length.

author: hamdi.tn
author_rank: Frequent Contributor
timestamp: August 05, 2014, 11:41:18 am
content: Quote from: mikerj on August 05, 2014, 10:53:43 amwell, right for a reader the CMSIS is easier to understand, for a developer those defined function are not well documented and the only available help i have found is some commented line in the library files, the usual procedure is to configure the peripheral with some constant name then call an init function, go figure what the stupid parameter is named, i jump from a library file to an other library file for that. but the registers are well explained in the data-sheet and there functionality is well defined. i think that's why some of us find it easier to work with registers directly.just to say, i had an other experience with bluegiga bt4 module (equipped with texas instrument uC) , they have there proper coding language and supply ready to use function, with huge amount of information and multiple documentation about those function , there parameter, return, and some good example on how and when they can be used. i had no trouble writing code for those chip despite the fact that i just used them for like few days.Quote from: mikerj on August 05, 2014, 10:53:43 amThat's the right conclusion i think

author: dannyf
author_rank: Super Contributor
timestamp: August 05, 2014, 11:51:51 am
content: QuoteLibraries have their own learning curve and follow their own approach which a programmer may not be able to grasp. They offer however more of a canned approach which makes them more portable.What you are talking about is NOT CMSIS - the core CMSIS is very limited in its functionality and unless recently is limited to simply starting up the chip (vendor supplied) and initializing the clock. What you are talking about are vendor supplied libraries.QuoteDirect register access is typically faster and has smaller foot print. They are typically hard to port and requires fairly good amount of upfront investment.Both approaches work for some people some of the times. It is foolish to be fixated on just one at the exclusion of the other.

author: mikerj
author_rank: Super Contributor
timestamp: August 05, 2014, 01:44:39 pm
content: Quote from: nctnico on August 05, 2014, 11:38:28 amBecause they are either misinformed or prone to ridiculous exaggeration at a guess. Each port has two configuration registers, an input data register, and output data register, a bit set/reset register, a bit reset register and a lock register. That's 7 registers per port and once you've configured it you only need to use a couple of those registers for setting or reading pin levels. It's hardly rocket science, and no more difficult than other micros.There is also a handful of AFIO (alternate function IO) registers that need to be configured once to select which peripherals are to use the various shared pins. Again, many other micros have pins shared between different peripherals, so this is nothing unusual.Quote from: nctnico on August 05, 2014, 11:38:28 amWithout the documentation to cross reference the register names they mean very little to someone that doesn't have significant experience with the LPC. I can guess that they are configuration registers for an SSP peripheral but beyond that I don't know what the individual bits do. With the STM32 example I can see immediately how the SPI has been configured without needing to refer to the reference manual.This is the kind of thing that would never pass a decent peer review. Even if you want to write directly to the registers, please use the bit definitions that should be supplied in the vendors libraries rather than magic numbers.

author: nctnico
author_rank: Super Contributor
timestamp: August 05, 2014, 01:58:59 pm
content: A decent peer review would check the configuration settings against the datasheets/user manuals of both the SPI slave and the controller. Who is to say the programmer choose the right CPHA, CPOL, word length options?Actually the CMSIS sample comes from Keil for configuring an NXP Cortex Mx chip.

author: dannyf
author_rank: Super Contributor
timestamp: August 05, 2014, 02:00:39 pm
content: QuoteMaybe they don't know what they are talking about or they cannot count? Who knows.But it is generally true that the numbers of registers / bits involved are significantly more than on a 8-bit chip. Because those peripherals are generally far more powerful than their counterparts on a 8-bit chip.

author: mikerj
author_rank: Super Contributor
timestamp: August 05, 2014, 02:55:21 pm
content: Quote from: nctnico on August 05, 2014, 01:58:59 pmThe programmer may well have selected the wrong SPI configuration, but the whole crux of my argument is that this kind of error would be far more obvious if magic numbers weren't used.Code reviews take a lot of time which is a busy engineers most precious resource, so why wouldn't you want to make their job as painless as possible by making your code clear and easy to read?

author: nctnico
author_rank: Super Contributor
timestamp: August 05, 2014, 03:24:55 pm
content: It would be magic numbers if a bunch of different settings where concatenated into one number. When setting a single bit I always use shifts which are orred together. It is easy to see which bits are set without needing to check the underlying macros.

author: dannyf
author_rank: Super Contributor
timestamp: August 05, 2014, 04:00:18 pm
content: QuoteYou have an understanding of "magic numbers" drastically different from the rest of the world's.

author: andyturk
author_rank: Frequent Contributor
timestamp: August 05, 2014, 04:18:10 pm
content: Quote from: nctnico on August 05, 2014, 09:20:52 amPersonally, I'd prefer the register poking version because it's easier to trace it's actions back to the datasheet for the SPI peripheral. The CMSIS version introduces two extra (potentially leaky) levels of abstraction: 1) ARM's CMSIS API, and 2) NXP's implementation of the CMSIS API. The chip's datasheet is the ultimate documentation reference regardless of how the code is written and the less that stands between the code and the doc, the better off you are. Stylistically, the register poking version would be more clear if it used some named constants (or maybe even constexprs) on the right-hand sides.That said, which code snippet you use is a lot less important than *where* the snippet appears.

author: dannyf
author_rank: Super Contributor
timestamp: August 05, 2014, 04:44:58 pm
content: QuoteLayering can help here: all you need to know is that spi_send() sends out a byte, regradless of the host machine. So you don't need to worry about loading up which registers and setting up which flags.Middleware is the way forward. Some are well executed (PE and RTE for example), some are not as well executed (ST's libraries), and others are poorly executed (Cube or LPCOpen). But those issues are reflective of the implementation / execution of such an approach, not an issue with the approach itself.

author: nctnico
author_rank: Super Contributor
timestamp: August 05, 2014, 04:49:38 pm
content: Named constants look better but... Recently I had to check the settings of a complex peripheral in a SoC to see whether the bootloader and Linux kernel used the correct & same settings. Because of the named constants I had to check the macros against the user manual, cross reference these between the bootloader and the Linux kernel and then check the code. A whole lot more work than just checking bit shifted / orred constants against the user manual.

author: gocemk
author_rank: Regular Contributor
timestamp: August 05, 2014, 07:05:09 pm
content: Since the thread was about "STM uC Vs Microchip uC" let me give you my experience on the topic:Up until recently i was using only Microchip 8-bit PIC mcu's to get some job done, either for hobby or for work. That's because they are cheap, i know them pretty well and are available where i come from. Even today they are my first choice for some "simple" custom automation project at work/home. A year ago i decided to try the 32-bit version of the PIC mcu, i.e PIC32 which packs a MIPS 4K core. I bought a development board with the strongest 32-bit chip microchip had to offer at that time: PIC32MX795F512H. The chip is quite fast, 1.56 DMIPS/Mhz, 80MHz, most instructions are single cycle, faster than Cortex M3 for DSP applications (293us vs. 360us for 256 point FFT) and easy learning curve coming from an 8-bit PIC background.BUT.....................soon after that i discovered the STM32F303 with ARM Cortex M4F core and a set of peripherals much, much, much richer and better than the PIC32. In fact, i think that to this day Microchip doesn't have to offer anything near the STM32F3 series, let alone the F4 series. As far as i know PIC32MZ with the new M14K core(microAptiv core) and 330DMIPS still has a bigger errata than a datasheet, and on the Microchip site is still listed as a "future product". And it doesn't even pack FPU. Recently, i finished a project done with the STM 32, which used 7-8 timers, UART and few other peripherals. Everything was done using the STM's libraries and i didn't had a single problem. IMO, the libraries are so self explanatory, that in most cases even comment's are obsolete. And using them you can easily port projects between STM32F families. Right now, my choice for ARM is exclusively STM32. I tried the NXP's LPC1769 with LPCXpresso, but the absence of proper libraries made the experience much more unpleasant.Oh...I almost forgot the best part: You can pick up an STM32F3/F4 dev. board with MEMS sensors and ST Link included for under 20$!!!!

author: dannyf
author_rank: Super Contributor
timestamp: August 05, 2014, 07:31:07 pm
content: QuoteThere is no hope for PIC32.QuoteI have no problem with the ST libraries (i2c being the exception) as well.QuoteIt is not that difficult to code those chips, even without a library. LPCOpen is a different story. The library distributed with CoIDE is robust.

author: djacobow
author_rank: Super Contributor
timestamp: August 05, 2014, 09:05:47 pm
content: Quote from: AndyC_772 on August 05, 2014, 09:07:19 amYes. This.Nobody here in their right mind is going to say "libraries are bad." Libraries are good, abstraction is good. But some don't don't actually DO all that much for you. They just replace some pokes of some registers with funny names and confusing constants and replace them with function calls with funny names and confusing constants, except now you have this layer of stuff in between that, if you are lucky, you won't every have to investigate but in all likelihood, you will soon be looking at to see exactly what it does anyway.This is not a criticism of the concept, but of the implementation.Think of a UART. What does a programmer want to see? Probably a function that lets him set up the UART (baud, bits, etc) as well as specify (potential) callbacks for full/empty send/receive buffers, and a few functions for sending and receiving. Now, that UART may be all-singing all-dancing withmany fancy modes, and so, by all means, provide more complex calls to do that stuff. But let the simple be simple.

author: hans
author_rank: Super Contributor
timestamp: August 05, 2014, 10:02:38 pm
content: At the company I work for, we write device drivers over the existing CMSIS library. We implement a simple to use CAN, UART and SPI drivers.. with just a simple TxByte(), TxString() and Initialize(Baudrate).If I need a very specific way of using timers with match interrupts, match pins etc.. I am probably going to download the datasheet and see how the peripheral works and which features to use. The CMSIS library adds little value in that case IMO; it just translates some bit values to typed names, which is a good habbit to have anyway.In fact, we have encountered some bugs or "non described side effects" on the LPC1768 CMSIS library. For example, I recall that you can only set the PWM duty cycle once per period on LPC1768, otherwise the PWM output will stick to '1' for that period. I believe there was a bug in the timer library (I believe capture input pins), where the interrupt flag was not cleared properly. That caused the interrupt to "stick", but fortunately that's immediately obvious during development and quickly fixed (that PWM side-effect was not, hard to track down).In general my experience with NXP is quite good. I've had a lot more issues with STM32 chips and in particular the ethernet peripheral, which is one of those peripherals where you just want to download a stable library and start sending MAC frames right away.

author: westfw
author_rank: Super Contributor
timestamp: August 05, 2014, 10:46:39 pm
content: QuoteThat was TI Stellaris. And it wasn't exactly a "complaint"; more an illustration of unexpected complexity...QuoteAh, but the CMSIS spi "driver" doesn't have "spi_send(byte)": it has ARM_SPI_Send (const void *data, uint32_t num), which "only starts the transmission" - you'll get a callback to your registered event function when the transmission is complete. nctnico's example doesn't include the implementation of the callback function, and the example on page he links to includes rtos/threading code of "unknown" importance. SPIDrv is also a data structure that occupies ~44 bytes, mostly pointers to lower-level functions that probably also have to be implemented (by the vendor library, hopefully.) (or does that all get optimized away, anyway?) It looks "as simple" as the raw bit-setting code, but it hides substantial (and "unknown" complexity.)The CMSIS driver functions all seem to have this callback based architecture. Arguably, these are exactly the sort of "new paradigm" that a "large microcontroller" should have, compared to the simpler byte oriented functions common on "small microcontrollers"; somewhat in between blocking, synchronous, function calls and a full OS-based scheme. It's hard to tell, and it makes me nervous when the "large microcontroller" vendors start offering those 32k/4k "8-bit replacements" and expect the same libraries to work.A good "abstraction" should be close to what the programmer wants to use; obvious, simple, and clear in the source code, and still possible to implement efficiently on the target. An abstraction that merely implements "equally painful" access to peripherals has some value, but is what I fear, rather than what I want. (A particular pet-peeve is bitmapped configuration values that don't map directly to configuration bit settings, leaving driver code sprinkled with awful "if (uartstruct->cfgbits & UART_8bits) ucfgabits |= UC0SZ0|UC0SZ1;" statements. I think the best "abstraction" that I've seen recently is the "pin" abstraction in Arduino; and it is rarely implemented as efficiently as it could be... I haven't used CMSIS enough to know how I'd rate it, but it only LOOKS so-so. (also, it's not very compatible with typical 8bit libraries, so it's not a big motivator to the people moving from 8bit.)AFACT, CMSIS doesn't define anything for GPIO...

author: nctnico
author_rank: Super Contributor
timestamp: August 06, 2014, 12:03:18 am
content: Quote from: westfw on August 05, 2014, 10:46:39 pmWith SPI and I2C (master) I usually wait for the transaction to finish. The software can't go further without the result anyway at that point. I run high priority processes from interrupts so it is no problem the slow housekeeping process is waiting for some relais to be set or an ADC to be read. With SPI set to 10MHz reading 16 bits takes 1.6us. With the interrupt latency typically at 0.3us there is not much to gain by setting up an interrupt and initialising/testing semaphores.

author: andyturk
author_rank: Frequent Contributor
timestamp: August 06, 2014, 02:33:21 am
content: Quote from: nctnico on August 06, 2014, 12:03:18 amYou do polling in an ISR?

author: westfw
author_rank: Super Contributor
timestamp: August 06, 2014, 04:37:31 am
content: QuoteYou mean like this (copying a function from ArduinoISP):Code:uint8_t avrisp_transaction(uint8_t a, uint8_t b, uint8_t c, uint8_t d) {uint8_t outdatat;uint8_t indata;outdata = a;outdata = b;outdata = c;outdata = d;spiDRV->ARM_SPI_Transfer(outdata, indata, 4);while (spiDRV->ARM_SPI_GetDataCount() < 4){ /* spin */ }return indata; // Last byte input is result.}

author: mikerj
author_rank: Super Contributor
timestamp: August 06, 2014, 08:35:46 am
content: Quote from: nctnico on August 06, 2014, 12:03:18 amThat is only true for extremely simple applications where you have just one task to execute. Many/most embedded systems have multiple tasks and the blocking of one does not have to (and usually should not) prevent execution of the others. Note that I'm using the word "task" in a non-RTOS sense here, because you don't need an RTOS to continue execution of other tasks when one is blocked.

author: tszaboo
author_rank: Super Contributor
timestamp: August 06, 2014, 09:59:03 am
content: Quote from: dannyf on August 05, 2014, 07:31:07 pmLooks like there is more information for the PIC32MZ than the last time I checked. I wouldn't say that PIC32 is a dead architecture. I actually think it is really decent, not because of the core, but because the peripherals microcip adds to its MCU.Look at the smallest MZ datasheet. 4 SPI, 6 UART (25 megabit) USB and ethernet in a LQFP64 package, and a 32 bit core running at 200 Mhz. SQI memory interface. I think it is impressive. I'm actually looking forward to try these. Thank for reminding.According to farnell, they will be at stock in mid October.

author: nctnico
author_rank: Super Contributor
timestamp: August 06, 2014, 10:17:13 am
content: Quote from: mikerj on August 06, 2014, 08:35:46 amThat is overthinking the whole situation. It is no problem to wait for a few us here & there. It is much less hassle than trying to build everything non blocking or event driven. In the end waiting a few us is probably more efficient than implementing the overhead for not having to wait.@andyturk: no polling inside the ISR!

author: dannyf
author_rank: Super Contributor
timestamp: August 06, 2014, 11:19:34 am
content: QuoteThat's the nature of the counter and true for all chips.To avoid it, use center-aligned pwm. or being careful in changing pwm -> test the counter value first.

author: andersm
author_rank: Super Contributor
timestamp: August 06, 2014, 11:44:30 am
content: Quote from: NANDBlog on August 06, 2014, 09:59:03 amThe PIC32MZ is really, really buggy. Even by Microchip standards. Study the errata carefully, and remember that the part was originally launched in late 2013 (with silicon revision 3!) and is still not generally available. Scuttlebutt is that they're doing afull redesignwhich will be out in about one year's time. On the plus side, that version supposedly will add an FPU.

author: nctnico
author_rank: Super Contributor
timestamp: August 06, 2014, 12:15:23 pm
content: Quote from: dannyf on August 06, 2014, 11:19:34 amThe easiest way is to enable an interrupt for the counter value which needs to be changed and make the change in the interrupt. Shadow registers which get read at the end of the PWM cycle would have been nicer though.

author: tszaboo
author_rank: Super Contributor
timestamp: August 06, 2014, 01:43:34 pm
content: Quote from: andersm on August 06, 2014, 11:44:30 amYou should know, that the PCB designer never reads errata

author: hamdi.tn
author_rank: Frequent Contributor
timestamp: August 06, 2014, 02:17:38 pm
content: Quote from: NANDBlog on August 06, 2014, 01:43:34 pmdamn right

author: mikerj
author_rank: Super Contributor
timestamp: August 06, 2014, 05:43:10 pm
content: Quote from: nctnico on August 06, 2014, 10:17:13 amIf it's literally a few microseconds then I'd agree, but an I2C transaction of say 16 bytes at 100kbit/s would mean you are tied up for over a millisecond.

author: nctnico
author_rank: Super Contributor
timestamp: August 06, 2014, 07:02:40 pm
content: If waiting a millisecond doesn't hurt then it is not a problem. The whole dogma 'don't poll and exit interrupts immediately' just makes no sense. It is just a matter of planning on where to spend the CPU time and that differs with each project.