Reliable low-range wireless-enabled MCU/hardware/stack suggestions - Page 1
Forum section: electronics / general

author: uer166
author_rank: Super Contributor
timestamp: May 24, 2022, 04:06:18 am
content: I'm thinking about designing an own wireless remote for a e-skate type application as a learning exercise about wireless. I'm looking for something that has a relatively easy-to use wireless function (can be bidirectional or one-way only from remote to motor control MCU).I have general embedded experience, but 0 knowledge about wireless stacks/hardware beyond the basics. It doesn't need to actually comply with any FCC regs since it's a one-off, but it does need to be quiet enough, and keep a low enough duty cycle to not jam anything or raise any eyebrows, and I suppose keep to the ISM bands.The major requirement is it needs to be absolutely reliable with a ~10ft range (for brake function on steep SF hills), maybe with some form or frequency hopping, as simple as possible with few states (e.g. BLE is out of the question). A minor requirement is that the MCU/chip can also crunch enough numbers, and have enough PWM peripherals for a full FOC motor controller. It need not be any standard protocol, or inter-operate with anything else, both sides would be custom-designed.Not interested in complete FCC-certified modules, need to be bare chips with ideally existing reference designs.

author: jeremy
author_rank: Super Contributor
timestamp: May 24, 2022, 05:01:43 am
content: I would suggesthttps://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/nrf/ug_esb.html#ug-esbLatency is much better than BLE. But you are likely going to have issues doing real-time motor control as well as with a radio, because typically these radio MCUs will set the radio interrupt as the highest priority.

author: uer166
author_rank: Super Contributor
timestamp: May 24, 2022, 05:16:05 am
content: I wonder if sub-GHz would have any advantage in test and layout, I've been looking at STM32WL and similar which have enough facilities for motor control and radio, but the tools only include Lora and Sigfox which seem to be more for long-range, low BW applications. Nordic's tools also seem much nicer for RF than ST..

author: jeremy
author_rank: Super Contributor
timestamp: May 24, 2022, 05:25:03 am
content: 2.4GHz has the advantage of smaller antennas, and lots of options available.I would not use LoRa for something like this as the on-air time is fairly long, but from what I recall the Semtech radios support raw FSK and GFSK too. Also keep in mind that (at least in AU), the legal maximum transmission duty cycle is a lot lower on 900MHz than 2.4GHz.Also, have you tried to actually buy an STM32WL device?At least the Nordic parts can still be found on aliexpress…

author: uer166
author_rank: Super Contributor
timestamp: May 24, 2022, 05:29:56 am
content: Quote from: jeremy on May 24, 2022, 05:25:03 amGood points on the antenna size and duty cycles! Yeah they do support raw FSK, but I don't have it in me to figure out a good protocol/stack quite yet, which is why a nice canned solution like that Nordic one seem to be the best bet.The STM parts seem to be (surprisingly?) somewhat available from major distributors:https://www.mouser.com/ProductDetail/STMicroelectronics/STM32WL55JCI6?qs=DPoM0jnrROVj9ZL1d6pcUg%3D%3Dhttps://www.digikey.com/en/products/detail/STM32WL55CCU7/497-STM32WL55CCU7-ND/13557443

author: pcprogrammer
author_rank: Super Contributor
timestamp: May 24, 2022, 06:10:52 am
content: Also easy to use and with lots of Arduino examples around are these CC1101 transceivers:https://nl.aliexpress.com/item/33058767500.htmlThe same goes for the Nordic NRF905 transceivers:https://nl.aliexpress.com/item/32902708683.htmlYou don't need special stacks. Just use them like uarts. Send bytes at one end and receive them at the other end and start an action based on that.See this project for example:https://github.com/elechouse/nRF905

author: Siwastaja
author_rank: Super Contributor
timestamp: May 24, 2022, 06:41:12 am
content: I took chances with the nRF52 family, specifically Fanstel modules, but you can easily just use the nRF chip as is. Some key findings so far:Hardware design and documentation is just excellent. This is the easiet-to-program (on register level!) MCU family I have ever used - including the RADIO peripheral!As a massive contrast, the SDK / official software ecosystem is one of the most horrible, most complex jobs ever. Simplest of examples compile tens of thousands of LoC, and do not work out of box. You can't even get hello world, because hello world is printed using a custom NIH "logging library", which requires configuration (10kLoC configuration file) to work. I spent hours trying to fix the logging library and gave up.In the end, I just needed radio comms (and had quite special custom requirements regarding timing and bandwidth), not compatibility with Bluetooth devices, so I did not use the Bluetooth stack at all. Went bare metal writing custom code for the RADIO peripheral.I started with the Enhanced ShockBurst example - that was actually possible to compile and use, worked almost out of box. The next step was to modify ESB example, changing the radio into BLE 125kbps LR mode - it requires a few modifications. But do beware - ESB is nothing special, it's quite primitive. You can easily surpass it with your own protocol. For example, adding resends and frequency hopping greatly improved the performance over the ESB example.For a simple one-off, you can go pretty far by something like this:Code:typedef struct __attribute__((packed)){uint8_t len;union{own_payload_type1_t own_payload_type1;uint8_t payload;}} packet_t; // remember to configure the packet structure in NRF_RADIO peripheral, so it automagically knows how wide len field is, maximum length of payload, etc.packet_t packet;packet_t.own_payload_type1 = {1,2,3,4,5};packet.len = sizeof (own_payload_type1_t);NRF_RADIO->FREQUENCY = 42; // 2442MHzNRF_RADIO->PACKETPTR = &packet; // the peripheral understands the len field in memory, and uses DMA to send the packet. Quite neat.NRF_RADIO->TXEN = 1;// poll for NRF_RADIO->EVENTS_DISABLED, or make it an ISRThis example shows how easy this is to use!Of course being who I am and preferring custom solutions, I ended up writing a full fancy protocol with pseudorandom/controllable frequency hopping, message buffering + resend requests, multi-slave timesharing etc. And I don't know if that made any sense, it took a couple of months in the end. But one thing is sure: the peripheral (HW) design and datasheet made the work much less painful than dealing with STM32, for example.nRF52 devices also have decent PWM peripheral (seems to have 4 compare registers) so it should be able to drive a motor if you use external half-bridge gate drivers with deadtime generation. It seems the thing does not have internal deadtime / negated outputs.But, regarding your reliability concern with braking - ISM bands is, by definition, out of question. You can't, and I can't stress this enough,by definition, build anything with delivery guarantee over ISM bands. This is because ISM is defined as frequency band not designed for communication; it's the band designed for interference from microwave ovens etc. The fact people started to communicate over a non-communication band tells an interesting story about the misery of political regulation, but that is what we need to live with.The best you could do is send a lot of small packets, frequency hopping over the whole band, but the problem is, any other device is allowed to wipe out that entire band any time. Then you must rely on physical separation, but how much is enough, this is hard to say.

author: uer166
author_rank: Super Contributor
timestamp: May 24, 2022, 06:46:41 am
content: Quote from: evb149 on May 24, 2022, 06:36:30 amWhat you say makes sense, but this is a learning exercise as much as a practical end result. Of course I would havesomeamount of fail-safe: e.g. a nice and slow ramp to full regen braking, or some sort of warning so I could switch to foot-brake. I've been thrown off one of these before due to a BMS cell UV fault (full torque to 0 torque tends to throw you off balance), and it's not fun, so I would like to avoid it as much as possible, but it's not the end of the world if it dies and simply goes into a coast.I would like it to be a reallynicesingle PCBA with everything: BMS, FOC motor controller, and radio. This is not how it's usually done, but again it's a fun project..The avoidance of a module is 2-fold: I would like to try some minimal amount of RF PCB layout and RF validation, and I would like to be fully in control of the mechanicals of the system.

author: Siwastaja
author_rank: Super Contributor
timestamp: May 24, 2022, 06:57:44 am
content: IMHO, you have two realistic choices:* Just add wires* Go wireless and accept the fact you are taking a very real risk of the communication failing. Make sure your "fail safe" logic does not kill or injure yourself or someone else.That being said, even if you add wires and have perfectly reliable communication (say, over current loop with optoisolation, or maybe RS422 or CAN), your motor control code can still misbehave, it's colossally difficult to write perfectly bug-free code.So maybe if you go wireless, that existing risk just goes up by maybe two orders of magnitude. Maybe you can accept it?But this is definitely something that calls for bare metal approach, i.e., no existing BLE stack.One thing I would consider is adding dual radio, on different ISM bands, for example one at 2.45GHz band, one at 915 or 434MHz. More work, yes, and dual-MCU solutions suck development-wise, but that's the price you would pay for significantly increased radio reliability. And you still have zeroguarantee.Am I guessing correctly you would be just transferring some simple motor control parameters like speed or torque (< 10 bytes payload), at a rate such as 10-50Hz? Is it going to be unidirectional, or you need status information back from the motors?

author: uer166
author_rank: Super Contributor
timestamp: May 24, 2022, 07:03:31 am
content: Quote from: Siwastaja on May 24, 2022, 06:57:44 am1) Thanks for the great info/experience2) Yup, uni-directional is fine. A few bytes at 10Hz say. Bi-directional is nice to have (BMS state, etc)I've also considered using some sort of IR transceiver a la TV remote, or IR headphones, but I suspect the power requirements in the remote to overcome the sun radiation would be way too much for the required size.

author: Siwastaja
author_rank: Super Contributor
timestamp: May 24, 2022, 07:08:59 am
content: Well, the first prototype is very quick to do on nRF52. Just flood the packets on a single frequency, a few dozen lines of code. Enable RX, poll for EVENTS_DISABLED, check if you have EVENTS_END and CRCSTATUS is valid. Rinse and repeat.Now with frequency hopping it gets a bit more difficult: you can't just keep listening anymore, you need to know when to listen, at what frequency.It's still quite simple, you just decide that for example, you hop over 10 frequencies and listen for 20ms on each. If you getanypacket through even once, you can synchronize the clocks, and being on the 32kHz watch crystal (for the Real-Time Counter peripheral on nRF52), the sync is good for minutes. Now you always know when to terminate RX, switch to the next frequency, and start RX again. Just a few dozen lines-of-code more.Bidirectionality makes it again more complex, you have to divide time into RX/TX slots. Not too hard; make that 20ms slot 15ms listening and 5ms transmitting a reply, on the same frequency. Bidirectionality enables your master to know when the connection is lost, so maybe you can brake down other motors in sync, using similar ramp to the fail-safe code.Your work is made somewhat easier by the fact you don't need to consider low-power operation (I'm assuming the "master" or controller side has decent battery as well. Motor side obviously does). So you can fill all unused time by just listening, and don't need a separate "sleep state" and special wakeup protocol.

author: uer166
author_rank: Super Contributor
timestamp: May 24, 2022, 07:18:05 am
content: That's more-or-less exactly what I had in mind. I just never realized how easy it seems to be to use the nRF hardware directly without all the BS. I've started reading through the STM32WL radio section in the reference manual and holy crap, I fully expected to dive into the weeds of modulation technique details and thousands of lines of setup and operational code. Seems like nRF hardware abstracts all that away and just works with whatever modulation/power/frequency settings you choose. I'm actually not convinced they don't have some embedded co-processor with ROM that essentially hides an otherwise large library.You're correct in assuming that the remote battery is not a problem, 500mAh is easy, and can be recharged every ride anyway. And of course the receiving end has 0 concerns with RF power use considering ~2kW motors and a ~600Wh battery.

author: Siwastaja
author_rank: Super Contributor
timestamp: May 24, 2022, 07:21:03 am
content: Yeah, if you have at leastsomeexperience writing MCU register level code, you have custom NRF_RADIO application transmitting and receiving packets in a day, only referring to the "Product Specification" sheet and about 20 pages regarding RADIO (ignoring Bluetooth addressing and direction finding parts).I recommend BLE LR 125kbps physical signalling for the best range (sensitivity). You get all the high-tech BLE radio signalling woodoo, without the higher level BLE protocol.

author: JPortici
author_rank: Super Contributor
timestamp: May 24, 2022, 07:24:09 am
content: Quote from: Siwastaja on May 24, 2022, 06:41:12 amNeat! I was reluctant to try them because of the SDK. I had next to horrible experiences with SiLabs and their tools and was even more scared when i started looking at nrf52 for other stuff

author: jeremy
author_rank: Super Contributor
timestamp: May 24, 2022, 01:36:09 pm
content: The nrf5 SDK is in maintenance only mode (ie they keep it alive for legacy customers, but otherwise you shouldn’t use it) and has been for some years now iirc. The Zephyr SDK is what Nordic expects you to use nowadays, and personally I think it is fantastic but the initial learning curve is very steep, particularly around the devicetree.I have used nrf52 devices for BLE quite a bit, and the contrast between the nrf5 and Zephyr SDK is like night and day. I am not a fan of the nrf5 SDK.Modules can be had for much cheaper from Chinese manufacturers “Ebyte” and “Minew” on Aliexpress (or direct from their websites). These are both official distributors for Nordic I believe. There is also this little guy:https://www.seeedstudio.com/Seeed-XIAO-BLE-nRF52840-p-5201.htmlbut it is so popular that it is permanently on backorder. I got mine after 4 months of being on the backorder list. Fanstel is good but their interesting modules all seem to be out of stock for the last year or so. There is also Raytac which I would say is the “go-to” module producer.The main problem with using these devices without a module is that you need capped blind microvias to fan out the nrf52840 (it is a weird double row aQFN package), and that makes your prototypes very expensive.

author: jeremy
author_rank: Super Contributor
timestamp: May 24, 2022, 01:41:40 pm
content: Quote from: uer166 on May 24, 2022, 07:18:05 amThey definitely do not have a co-processor (except in the nrf5340 in which this is a feature) unless you consider a state machine a coprocessor. For BLE, it uses a “supervisor” model like the Dialog Semi parts. Basically, the “SoftDevice” (their radio firmware) is in control on the main CPU, and it passes you the execution as long as it isn’t busy itself.

author: Siwastaja
author_rank: Super Contributor
timestamp: May 24, 2022, 03:52:33 pm
content: Quote from: jeremy on May 24, 2022, 01:36:09 pmInteresting to know. Just half a year ago, I spent some 30-40 working hours of work trying to learn and work with/around the nRF52 SDK, and nowhere I found this piece of information. Quite the opposite, the SDK was the only thing they referred anyone to.But it became obvious it would be a few months of full time job to be able to actually develop anything with that complex pile of shit. The problem - once you invest many man-months in it (or man-years, if using less experienced developers), then you get to hear "oh btw, it's now deprecated, here's a new equally difficult pile of bullcrap with steep learning curve again and oh by the way,thissnake oil is the best thing since sliced bread".The funny part:* Peripherals are well designed and easy to use.* The general idea of SoftDevices - using software interrupts to interface the library, removing compile and link time dependencies - even easier than classical "libraries", just flash the SoftDevice somewhere - is very good.But all this is wasted by the fact that the process is undocumented and with zero examples. They only refer you to the SDK, and SDK examples. Which means, using it requires understanding which file of the 50 files and 100000LoC to start modifying. No "BLE hello world" anywhere. Instead of blinking an LED with one (1) line of code, they have a Button And LED Service, abbreviated BLS like it's some new fancy TLA, somewhere deep in the source tree.I took the easy way out - just did not learn to use BLE. For me it was fine because I did not need interoperability with smartphones. The OP seems to have a very similar case.

author: Marco
author_rank: Super Contributor
timestamp: May 24, 2022, 11:20:16 pm
content: I'd trust enhanced shockburst with your own frequency hopping over anything bluetooth.

author: uer166
author_rank: Super Contributor
timestamp: May 25, 2022, 06:08:09 am
content: Quote from: jeremy on May 24, 2022, 01:36:09 pmLuckily I'm looking at the smaller brothers such as nRF52811 in a nice and benign QFN48. I'd never use that weird 2-row package in such a high vibration environment anyway. Hope the QFN has wettable flanks so it can be checked.

author: JPortici
author_rank: Super Contributor
timestamp: May 25, 2022, 09:54:33 am
content: Quote from: uer166 on May 25, 2022, 06:08:09 amit looks like the very retarded VTLA that microchip used for some time (if i can name one good thing of chippageddon is that those parts were EOL'd and will never return to haunt us)

author: uer166
author_rank: Super Contributor
timestamp: May 25, 2022, 10:49:51 pm
content: Ordered some EV-BM833AF boards with a nRF52811, nice that the JTAG and USB and UARTs are all exposed. No idea what kind of libraries Fanstel provides, but hopefully can simply fire up Nordic's IDE and get in there right away.

author: Siwastaja
author_rank: Super Contributor
timestamp: May 26, 2022, 06:20:35 am
content: Quote from: uer166 on May 25, 2022, 10:49:51 pmI started with EV-BC833 boards. I don't think Fanstell provides any useful code? Anyway, I spent a week trying to do something with the nRF SDK, got some Hello World compiled and running, failing to print Hello World. Also got Enhanced ShockBurst example successfully running, but that already required some modification. Then I modified the ESB code to switch it to BLE LR 125kbps mode.What I finally did? Took my previous STM32 project, linker scripts and startup code and just modified with the correct memory addresses referencing to the nRF52 datasheet. Flash withnrfjprog. First LED blinker running in an hour.Freely configurable IO mapping is the best thing since sliced bread!Fanstell Evaluation boards do not seem to match their datasheets, pin mapping is all different, go figure. This wastes some time. At least one of the LEDs was in the documented pin, another LED was not, and buttons were not.A few months forward, I have my full custom radio protocol which works really well and I can also see the actual operating range is better than with the ESB, thanks to frequency hopping. It really makes a difference if you are behind some rebar concrete. My protocol is ACKless and based on periodic transmissions at known times, and retransmission requests being sent only when necessary. Every periodic transmission is followed by 1 to 4 rx-tx slot pairs, each at different frequency, so that missing periodic packets can be re-requested instantly, not messing up packet order. Only when there retransmissions fail too (resend requests getting queued in a FIFO), packet order starts to change, which can be seen from the sequence numbering.

author: uer166
author_rank: Super Contributor
timestamp: May 29, 2022, 04:06:09 am
content: Not gonna lie the first experience with the dev board is a little disappointing. They actually recommend buying the official nRF52DK dev board to use as a programmer for EV-BM833A, which is a little confusing. If I knew I had to do that I'd have bought the official dev board from the start anyway..Regardless, I've been trying to use a ST-Link off of a Nucleo board to talk to the nRF52 chip on the Fanstel board without too much success. Something's happening but it seems to hang.. The MDK provided seems nice and minimal, and vanilla GCC compiles stuff fine, if only I could connect to the board. I'm also finding a lack of documentation regarding what official debuggers/tools are supported.If anyone has any recommendation about how to program/connect/debug in command line ideally that would be great. I'm used to canned solutions from vendors (such as STM32Cube and Mplab-X, but Nordic does not provide such things, so it's a learning experience).Code:$ ../openocd/bin/openocd.exe -f ../openocd/scripts/interface/stlink-dap.cfg -f ../openocd/scripts/target/nrf52.cfg -c "gdb_flash_program $ ../openocd/bin/openocd.exe -f ../openocd/scripts/interface/stlink.cfg -f ../openocd/scripts/target/nrf52.cfg -c "gdb_flash_program enable" -c "gdb_breakpoint_override hard"xPack OpenOCD x86_64 Open On-Chip Debugger 0.11.0+dev (2022-03-25-17:32)Licensed under GNU GPL v2For bug reports, readhttp://openocd.org/doc/doxygen/bugs.htmlInfo : auto-selecting first available session transport "hla_swd". To override use 'transport select <transport>'.Info : The selected transport took over low-level target control. The results might differ compared to plain JTAG/SWDnRF52 device has a CTRL-AP dedicated to recover the device from AP lock.A high level adapter (like a ST-Link) you are currently using cannot accessthe CTRL-AP so 'nrf52_recover' command will not work.Do not enable UICR APPROTECT.force hard breakpointsInfo : Listening on port 6666 for tcl connectionsInfo : Listening on port 4444 for telnet connectionsInfo : clock speed 1000 kHzInfo : STLINK V3J7M2 (API v3) VID:PID 0483:374EInfo : Target voltage: 3.297211Warn : target nrf52.cpu examination failedInfo : starting gdb server for nrf52.cpu on 3333Info : Listening on port 3333 for gdb connectionsshutdown command invoked

author: jeremy
author_rank: Super Contributor
timestamp: May 29, 2022, 05:48:20 am
content: Nordic does provide such a thing, it is a command line tool called "nrfjprog". But you need to use a J-Link with it. Normally I would just say to get a J-Link EDU and be done with it (they are like $20 from what I recall:https://www.digikey.com/en/products/detail/segger-microcontroller-systems/8-08-91-J-LINK-EDU-MINI/7387472) but due to the component shortages they are impossible to buy. You are probably better off just buying a dev kit. The nrf52dk is not too expensive.

author: Siwastaja
author_rank: Super Contributor
timestamp: May 29, 2022, 06:55:09 am
content: I just bought the recommended nRF52DK (and just use it as a Segger JLINK programmer) because this was paid work so wanted to minimize wasted time. Indeed, I'm usingnrfjprogwith it and... it just works. It's a bit confusing that if you miswire the JTAG, or just forget to power your actual target, then the nRF52DK silently targets the device on the nRF52DK itself, so you every now and then accidentally end up programming your binary on it... and even when it's a different MCU, it seems to be binary compatible enough that the RADIO does weird things! So then you want to erase it.However, I did hand out prototypes of own BM833 (nRF52833) based design with just SWD connector exposed to someone who normally only deals with STM32 and said "try programming it". He succeeded with it, apparently, but I don't know what he exactly did.

author: uer166
author_rank: Super Contributor
timestamp: May 29, 2022, 07:08:24 am
content: Quote from: Siwastaja on May 29, 2022, 06:55:09 amYeah I'd use nrfjprog, but still want full gdb/debugger access eventually (I know it's not needed, but I like looking at registers and single step). I ordered a J-link clone and a ST-link V2 (not V3), which hopefully has better compatibility with openocd and other various tools. J-link EDU is like $250 and the mini is unobtanium as was mentioned.So far I have tried:Upgrading the Nucleo/ST-link to be J-link compatible: apparently not possible because mine is V3, but V2 supposedly worksAttempt to patch and re-compile openocd which is apparently required to fix some stuff on nrf52. After a few hours of trying to make the build work in Cygwin I gave up: many errors and non-trivial setup/patch/merge/compilation issues.Some embedded DFU/UART bootloader in the chip would have beenreallyhandy right about now. Hopefully this is just a lack of proper tools issue, but boy this is more difficult than any other targets I've developed for (Freescale stuff, many STM32, STM8, dsPIC/PIC24, etc)..

author: jeremy
author_rank: Super Contributor
timestamp: May 29, 2022, 07:23:49 am
content: If you want GDB in particular, you can use openocd with a J-Link. You can also use segger Ozone (this is what I use) for single stepping, register poking, memory dumping, etc. It is kind of like a GDB GUI in a sense. You also have Segger SystemView for running traces of threads in Zephyr, and also segger RTT aka UART over JTAG. All of these tools work on basically any ARM processor (except some of the obscure ones from Chinese manufacturers, those used hacked J-Link binaries or something?). Honestly for me Ozone and RTT has been worth the price of the J-Link many times over.If you want an IDE, Nordic provides free licenses for Segger Embedded Studio, as well as a plugin setup for VSCode (the latter is what I use). Both can do single step debugging.

author: Siwastaja
author_rank: Super Contributor
timestamp: May 29, 2022, 07:46:08 am
content: Hey, here's a small code snippet that makes debugging much easier than looking at registers in debugger.Because the issue is always with timing with two separate devices. How the hell do you know if one isactuallylistening exactly when it should? Mere mortals like us do not have access to radio analyzers, and even if we had, we couldn't know if someone's listening or not. Maybe it would be possible to run two debuggers (one at both ends) and make sure register readout latency is minimized and somehow synchronize the debuggers... But this is easier:Code:#ifdef SCOPE_OUTPUTNRF_GPIOTE->CONFIG = GPIOTE_TASK | GPIOTE_PIN(0,28) | GPIOTE_TOGGLE | GPIOTE_INITIAL(0);NRF_PPI->CH.TEP = (uint32_t)&NRF_GPIOTE->TASKS_SET;NRF_PPI->CH.TEP = (uint32_t)&NRF_GPIOTE->TASKS_CLR;NRF_PPI->CH.EEP = (uint32_t)&NRF_RADIO->EVENTS_READY;NRF_PPI->CH.EEP = (uint32_t)&NRF_RADIO->EVENTS_DISABLED;NRF_PPI->CHENSET = 0b11UL<<10;NRF_GPIOTE->CONFIG = GPIOTE_TASK | GPIOTE_PIN(0, 3) | GPIOTE_TOGGLE | GPIOTE_INITIAL(0);NRF_PPI->CH.TEP = (uint32_t)&NRF_GPIOTE->TASKS_SET;NRF_PPI->CH.TEP = (uint32_t)&NRF_GPIOTE->TASKS_CLR;NRF_PPI->CH.EEP = (uint32_t)&NRF_RADIO->EVENTS_ADDRESS;NRF_PPI->CH.EEP = (uint32_t)&NRF_RADIO->EVENTS_END;NRF_PPI->CHENSET = 0b11UL<<12;#endif... and my helpers on which this code relies on:Code:// Example: HI(P0, 5);#define HI(port, idx) do{(NRF_ ## port)->OUTSET = 1UL<<(idx);}while(0)#define LO(port, idx) do{(NRF_ ## port)->OUTCLR = 1UL<<(idx);}while(0)#define IN(port, idx) ((NRF_ ## port)->IN & (1UL<<(idx)))#define IN_LOGICAL(port, idx) (!!((NRF_ ## port)->IN & (1UL<<(idx))))#define IN_SHIFTED(port, idx) (((NRF_ ## port)->IN & (1UL<<(idx)))>>idx)#define IO_TO_PULLUP_GPI(port, idx) do{ uint32_t _tmp_ = (NRF_ ## port)->PIN_CNF; _tmp_ &= ~(0b1111UL<<0); _tmp_ |= 3UL<<2; (NRF_ ## port)->PIN_CNF = _tmp_; }while(0)#define IO_TO_GPI(port, idx) do{ uint32_t _tmp_ = (NRF_ ## port)->PIN_CNF; _tmp_ &= ~(0b1111UL<<0); (NRF_ ## port)->PIN_CNF = _tmp_; }while(0)#define IO_TO_GPO(port, idx) do{(NRF_ ## port)->DIRSET = 1UL<<(idx);}while(0)#define IO_TO_ANALOG(port, idx) do{ uint32_t _tmp_ = (NRF_ ## port)->PIN_CNF; _tmp_ |= 1UL<<1; (NRF_ ## port)->PIN_CNF = _tmp_; }while(0)#define IO_PULLUP_ON(port, idx) do{ uint32_t _tmp_ = (NRF_ ## port)->PIN_CNF; _tmp_ &= ~(0b11UL<<2); _tmp_ |= 3UL<<2; (NRF_ ## port)->PIN_CNF = _tmp_; }while(0)#define IO_PULLDOWN_ON(port, idx) do{ uint32_t _tmp_ = (NRF_ ## port)->PIN_CNF; _tmp_ &= ~(0b11UL<<2); _tmp_ |= 1UL<<2; (NRF_ ## port)->PIN_CNF = _tmp_; }while(0)#define IO_PULLUPDOWN_OFF(port, idx) do{ uint32_t _tmp_ = (NRF_ ## port)->PIN_CNF; _tmp_ &= ~(0b11UL<<2); (NRF_ ## port)->PIN_CNF = _tmp_; }while(0)#define GPIOTE_DISABLED (0UL<<0)#define GPIOTE_EVENT (1UL<<0)#define GPIOTE_TASK (3UL<<0)#define GPIOTE_PIN(port,idx) ((port)<<13 | (idx)<<8)#define GPIOTE_LOHI (1UL<<16)#define GPIOTE_HILO (2UL<<16)#define GPIOTE_TOGGLE (3UL<<16)#define GPIOTE_INITIAL(x) ((x)<<20)With this, you get 2 oscillosscope channels per device so 4-channel oscillosscope/logic analyzer can show what's going on with two devices. One channel shows if the radio is currently enabled (listening or sending), and another goes high when ADDRESS is succesfully received/sent and back low when the packet ends. So you can instantly see if your TX/RX slots are aligned at correct times. By setting the vertical scale and offset so that '1' is on-screen but '1' is off-screen, and channels are stacked on top of each other, you get a very nice line diagram.

author: uer166
author_rank: Super Contributor
timestamp: June 05, 2022, 12:19:25 am
content: Quick update: I was finally able to connect and program some (garbage for now) stuff using a clone STLink-V2. A legitimate STLink-V3 as well as a Nucleo didn't work, and neither did a clone JLink-V9. This was certainly a painful way to get where I am so I would recommend just going the devkit (or legit JLink + Segger IDE) way to any passer-bys:Code:$ ../openocd/bin/openocd.exe -f interface/stlink.cfg -f target/nrf52.cfg -c init -c "nrf5 mass_erase" -c "program image.elf verify" -c resetxPack OpenOCD x86_64 Open On-Chip Debugger 0.11.0+dev (2022-03-25-17:32)Licensed under GNU GPL v2For bug reports, readhttp://openocd.org/doc/doxygen/bugs.htmlInfo : auto-selecting first available session transport "hla_swd". To override use 'transport select <transport>'.Info : The selected transport took over low-level target control. The results might differ compared to plain JTAG/SWDnRF52 device has a CTRL-AP dedicated to recover the device from AP lock.A high level adapter (like a ST-Link) you are currently using cannot accessthe CTRL-AP so 'nrf52_recover' command will not work.Do not enable UICR APPROTECT.Info : clock speed 1000 kHzInfo : STLINK V2J29S7 (API v2) VID:PID 0483:3748Info : Target voltage: 2.578525Info : [nrf52.cpu] Cortex-M4 r0p1 processor detectedInfo : [nrf52.cpu] target has 6 breakpoints, 4 watchpointsInfo : starting gdb server for nrf52.cpu on 3333Info : Listening on port 3333 for gdb connectionsInfo : nRF52811-QFAA(build code: A0) 192kB Flash, 24kB RAMInfo : Mass erase completed.target halted due to debug-request, current mode: ThreadxPSR: 0x01000000 pc: 0xfffffffe msp: 0xfffffffc** Programming Started **Warn : Adding extra erase range, 0x00000c68 .. 0x00000fff** Programming Finished **** Verify Started **** Verified OK **Now the new challenge is I am trying to set up a build environment from scratch (no SDK or IDEs). So far I've figured that I need 3 things:Nordic nRF MDK, which has all the register headers, linker files, and a (suspicious) startup codeARM CMSIS since the MDK stuff needs core_cm4.hGNU Arm Embedded Toolchain for compilers/linkers/GDBI've had a hell of a time trying to understand what options are required to cross-compile the startup code, as well as link properly, and got into all sorts of woods regarding C runtime, specs, standard libraries, etc. I've finally been able to generate a .ELF using:Code:arm-none-eabi-gcc.exe -DNRF52811_XXAA -I . -mthumb -mcpu=cortex-m4 --specs=nosys.specs -o image.elf -T nrf52811_xxaa.ld gcc_startup_nrf52811_new.S main.c -L GNU\ Arm\ Embedded\ Toolchain/10\ 2021.10/arm-none-eabi/lib/ -L GNU\ Arm\ Embedded\ Toolchain/10\ 2021.10/lib/gcc/arm-none-eabi/10.3.1/ -I ../CMSIS_5/CMSIS/Core/Include/Time will tell if I can blink an LED with this.

author: cv007
author_rank: Frequent Contributor
timestamp: June 05, 2022, 03:09:15 am
content: Its less complicated than it appears, at least until it gets complicated.An nRF52810 module I have, just blinking its led's-https://godbolt.org/z/xKW38hEorThis is all-in-one just to show its not difficult- my own linker script (commented out just to show in online compiler), my own startup code, all c++, no makefile, pretty simple (yes I tested it, and actually works, all info is contained in this simple example). I used the nRF52 Gpio class I already created, but 'lifted' the startup code and linker script from my stm32 projects. Its all mostly the same process for each mcu- get a datasheet, get a compiler, create code, program. Manufacturers seem to complicate the whole process.I started with a Nordic nRF52 usb dongle, and my debugger was blinking error codes on its led's (via my gpio class, which was first written before using mcu). Eventually ended up with a mix of Nordic code and my own to get what I wanted-https://github.com/cv007/nRF52_BroadcastTemperature(probably not very readable, but it works)Later I bought the nRF52 dev board and used seggerRTT to 'print' my debug info, which is much better than counting led blinks. I also used it to program some nrf52810 based modules, and also then had vscodium doing the build/program via tasks (usb dongle still needs Nordic desktop app to program). I have that dev kit still spitting out debug info via seggerRTT, and has been for many months so segger must be doing something right. I prefer debugging via 'print', and if seggerRTT is available it becomes easy/fast since swd is most likely already connected.I wanted ble so had to deal with everything that comes along with it (yuck), but if no need for ble/softdevice then I would probably start with a blank slate as I did in the example at the top of this post.

author: uer166
author_rank: Super Contributor
timestamp: June 05, 2022, 03:23:08 am
content: Oh that's cool!My usual pattern pretty much project is using an NTShell in the foreground for any an all debugging, and everything done in one periodic interrupt + nested higher priority ISRs as needed. That gives you a nice shell to interact with, issue commands, print and scope on a UART, etc, without affecting timing on the higher priority ISR(s) that do the actual work, which is why I don't care for the RTT or other non-standard printf-esque facilities.Now, this chip only hasoneUSART, and generally just lacking in peripherals, so I may need to figure out something else.

author: uer166
author_rank: Super Contributor
timestamp: June 05, 2022, 04:59:17 am
content: Latest problem seems to be that the GCC-provided crt0.s does not call main(). Not sure why, and I am not the only one with the issue:https://devzone.nordicsemi.com/f/nordic-q-a/28140/main-not-calledAs far as I can tell I am linking with thumb (which was the issue for one of the posters in Nordic forum):Code:/c/Program\ Files\ \(x86\)/GNU\ Arm\ Embedded\ Toolchain/10\ 2021.10/bin/arm-none-eabi-gcc.exe -DNRF52811_XXAA -I . -mthumb -mcpu=cortex-m4 --specs=nano.specs -o image.elf -T nrf52811_xxaa.ld gcc_startup_nrf52811.S main.c -L /c/Program\ Files\ \(x86\)/GNU\ Arm\ Embedded\ Toolchain/10\ 2021.10/arm-none-eabi/lib/ -L /c/Program\ Files\ \(x86\)/GNU\ Arm\ Embedded\ Toolchain/10\ 2021.10/lib/gcc/arm-none-eabi/10.3.1/ -I ../CMSIS_5/CMSIS/Core/Include/So uh, no idea what's happening behind the scenes and which crt0.o it's picking up. Seems like ARM supplies a precompiled version that I can't really look inside.To be clear, SystemInit() is definitely called from the Nordic startup file, but the call to _start, or __START, or whatever is called does not result in main() getting called:Code:/* LED pins aclive low: P17, P18, P19, P20 *//* Eval board: BM833AF *//* Chip: nrf52811 */#include <nrf.h>void SystemInit(void) // Gets here{asm("nop");asm("ADD R1, R1, R1");}int main(int argc, char *argv[]) // Never gets here{NRF_P0->PIN_CNF = 0x00000001;NRF_P0->PIN_CNF = 0x00000001;NRF_P0->PIN_CNF = 0x00000001;NRF_P0->PIN_CNF = 0x00000001;while(1){asm("nop");}}

author: cv007
author_rank: Frequent Contributor
timestamp: June 05, 2022, 06:26:18 am
content: Make the linker produce a Map file, and get an lss listing produced via objdump. _mainCRTStartup is probably the same symbol address as _start, so you may be looking for the wrong symbol. You will just have to follow the trail with the help of the map file and lss listing.Previous example used templates for Gpio class, but is not necessary and mostly not worth the trouble (more efficient, but not a big deal). Rewrite without templates-https://godbolt.org/z/EGMoePse5(still blinks led's ok). Is quite nice when you are in control of everything.You could also try the example if you wanted, with your led's-https://godbolt.org/z/YM9oxo9Kashould work for an 811 just the same as an 810.

author: uer166
author_rank: Super Contributor
timestamp: June 05, 2022, 07:02:00 am
content: Yeah from what I gather _start just goes to _mainCRTStartup at address 0x248. I've finally got GDB going and everything executes fine until it hits any of the code from crt0.o (precompiled):Code:Breakpoint 1, SystemInit () at main.c:10warning: Source file is more recent than executable.10 asm("nop");(gdb) stephalted: PC: 0x0000030611 asm("push {R3}");(gdb) stephalted: PC: 0x0000030813 asm("ADD R1, R1, R1");(gdb) stephalted: PC: 0x0000030ahalted: PC: 0x0000030chalted: PC: 0x0000030ehalted: PC: 0x000002d6Reset_Handler () at gcc_startup_nrf52811.S:284284 bl __START(gdb) stephalted: PC: 0x00000248Program received signal SIGINT, Interrupt.HardFault_Handler () at gcc_startup_nrf52811.S:304304 b .(gdb) halted: PC: 0x000002eehalted: PC: 0x000002eeI've been at this for hours now and no closer to figuring it out except maybe giving up on the GNU-supplied crt0.o without understanding why it hardfaults there. I've inspected the cause register and it seems that the only bit set is UNDEFINSTR inside UFSR, so some sort of broken instruction? It seems to happen as soon as it hits the first crt0.o instruction which is ""248: 4b17 ldr r3, [pc, #92] ; (2a8 <_mainCRTStartup+0x60>)" in the disassembly listing. I've also looked at assembling of the actual opcodes online and everything seems to check out. After reading how "easy" it is to set-up a bare toolchain on this forum multiple times, I have to say that I utterly disagree

author: Siwastaja
author_rank: Super Contributor
timestamp: June 05, 2022, 07:18:05 am
content: Try this: it's for nRF52833 so minor modifications of memory addresses etc. might be needed, but anyways:main.cCode:#include <stdint.h>#include "ext_include/nrf52833.h"#include "nrf_helpers.h"void delay_us(uint32_t i){i *= 7;i -= 7;while(i--)__asm__ __volatile__ ("nop");}void delay_ms(uint32_t i){while(i--){delay_us(1000);}}#define LED1_ON() do{LO(P0, 10);}while(0)#define LED1_OFF() do{HI(P0, 10);}while(0)#define LED2_ON() do{LO(P0, 20);}while(0)#define LED2_OFF() do{HI(P0, 20);}while(0)void uart_print(const char *buf){NRF_UART0->TASKS_STARTTX = 1;while(buf != 0){NRF_UART0->TXD = buf;while(!NRF_UART0->EVENTS_TXDRDY);NRF_UART0->EVENTS_TXDRDY = 0;buf++;}NRF_UART0->TASKS_STOPTX = 1;}void main(){IO_TO_GPO(P0, 10);IO_TO_GPO(P0, 20);LED2_ON();//Uncomment after LED blinking with the default RC clock has been verified, for more accurate clock for UART//NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;//NRF_CLOCK->TASKS_HFCLKSTART = 1;//while(!NRF_CLOCK->EVENTS_HFCLKSTARTED) ;LED2_OFF();NRF_UART0->PSEL.TXD = (0<<5) | 4;NRF_UART0->PSEL.RXD = (1<<5) | 9;NRF_UART0->BAUDRATE = 0x01D7E000; // 115200 baud (actual rate: 115942)NRF_UART0->ENABLE = 4;while(1){LED2_ON();delay_ms(1000);LED2_OFF();delay_ms(1000);uart_print("hello worldings\r\n");}}nrf_helpers.hCode:/*Simple low-level hardware abstraction, basically shorter, easily remembered names for the widely used registers*/#pragma once#ifndef NULL#define NULL ((void*)0)#endif#ifndef PACK#define PACK __attribute__((packed))#endif#ifndef ALWAYS_INLINE#define ALWAYS_INLINE static inline __attribute__((always_inline))#endif// Example: HI(P0, 5);#define HI(port, idx) do{(NRF_ ## port)->OUTSET = 1UL<<(idx);}while(0)#define LO(port, idx) do{(NRF_ ## port)->OUTCLR = 1UL<<(idx);}while(0)#define IN(port, idx) ((NRF_ ## port)->IN & (1UL<<(idx)))#define IN_LOGICAL(port, idx) (!!((NRF_ ## port)->IN & (1UL<<(idx))))#define IN_SHIFTED(port, idx) (((NRF_ ## port)->IN & (1UL<<(idx)))>>idx)#define IO_TO_GPI(port, idx) do{(NRF_ ## port)->DIRCLR = 1UL<<(idx);}while(0)#define IO_TO_GPO(port, idx) do{(NRF_ ## port)->DIRSET = 1UL<<(idx);}while(0)#define IO_TO_ANALOG(port, idx) do{ uint32_t _tmp_ = (NRF_ ## port)->PIN_CNF; _tmp_ |= 1UL<<1; (NRF_ ## port)->PIN_CNF = _tmp_; }while(0)#define IO_PULLUP_ON(port, idx) do{ uint32_t _tmp_ = (NRF_ ## port)->PIN_CNF; _tmp_ &= ~(0b11UL<<2); _tmp_ |= 3UL<<2; (NRF_ ## port)->PIN_CNF = _tmp_; }while(0)#define IO_PULLDOWN_ON(port, idx) do{ uint32_t _tmp_ = (NRF_ ## port)->PIN_CNF; _tmp_ &= ~(0b11UL<<2); _tmp_ |= 1UL<<2; (NRF_ ## port)->PIN_CNF = _tmp_; }while(0)#define IO_PULLUPDOWN_OFF(port, idx) do{ uint32_t _tmp_ = (NRF_ ## port)->PIN_CNF; _tmp_ &= ~(0b11UL<<2); (NRF_ ## port)->PIN_CNF = _tmp_; }while(0)init.cCode:/*Startup code before main(). Memory regions are defined in linker.ld, which exports symbols used here.*/#include <stdint.h>#include "ext_include/nrf52833.h"#include "nrf_helpers.h"void nrf_init();// add some kind of handlers, e.g. LED blinkers in infinite loopsvoid early_nmi_handler();void early_hardfault_handler();void early_mm_handler();void early_busfault_handler();void early_usagefault_handler();void invalid_handler();extern void main();extern unsigned int _STACKTOP;#define INITIAL_VECTOR_TBL_LEN (16+48)#define FULL_VECTOR_TBL_LEN (16+48)unsigned int * the_nvic_vector __attribute__ ((section(".nvic_vector"))) ={/* 0x0000 */ (unsigned int *) &_STACKTOP,/* 0x0004 -15 RESET */ (unsigned int *) nrf_init,/* 0x0008 -14 NMI */ (unsigned int *) early_nmi_handler,/* 0x000C -13 HARDFAULT */ (unsigned int *) early_hardfault_handler,/* 0x0010 -12 MEMMANAGE */ (unsigned int *) early_mm_handler,/* 0x0014 -11 BUSFAULT */ (unsigned int *) early_busfault_handler,/* 0x0018 -10 USAGEFAULT */ (unsigned int *) early_usagefault_handler,/* 0x001C -9 */ (unsigned int *) invalid_handler,/* 0x0020 -8 */ (unsigned int *) invalid_handler,/* 0x0024 -7 */ (unsigned int *) invalid_handler,/* 0x0028 -6 */ (unsigned int *) invalid_handler,/* 0x002C -5 */ (unsigned int *) invalid_handler,/* 0x0030 -4 */ (unsigned int *) invalid_handler,/* 0x0034 -3 */ (unsigned int *) invalid_handler,/* 0x0038 -2 */ (unsigned int *) invalid_handler,/* 0x003C -1 */ (unsigned int *) invalid_handler,/* 0x0040 0 */ (unsigned int *) invalid_handler,/* 0x0044 1 */ (unsigned int *) invalid_handler,/* 0x0048 2 */ (unsigned int *) invalid_handler,/* 0x004C 3 */ (unsigned int *) invalid_handler,/* 0x0050 4 */ (unsigned int *) invalid_handler,/* 0x0054 5 */ (unsigned int *) invalid_handler,/* 0x0058 6 */ (unsigned int *) invalid_handler,/* 0x005C 7 */ (unsigned int *) invalid_handler,/* 0x0060 8 */ (unsigned int *) invalid_handler,/* 0x0064 9 */ (unsigned int *) invalid_handler,/* 0x0068 10 */ (unsigned int *) invalid_handler,/* 0x006C 11 */ (unsigned int *) invalid_handler,/* 0x0070 12 */ (unsigned int *) invalid_handler,/* 0x0074 13 */ (unsigned int *) invalid_handler,/* 0x0078 14 */ (unsigned int *) invalid_handler,/* 0x007C 15 */ (unsigned int *) invalid_handler,/* 0x0080 16 */ (unsigned int *) invalid_handler,/* 0x0084 17 */ (unsigned int *) invalid_handler,/* 0x0088 18 */ (unsigned int *) invalid_handler,/* 0x008C 19 */ (unsigned int *) invalid_handler,/* 0x0090 20 */ (unsigned int *) invalid_handler,/* 0x0094 21 */ (unsigned int *) invalid_handler,/* 0x0098 22 */ (unsigned int *) invalid_handler,/* 0x009C 23 */ (unsigned int *) invalid_handler,/* 0x00A0 24 */ (unsigned int *) invalid_handler,/* 0x00A4 25 */ (unsigned int *) invalid_handler,/* 0x00A8 26 */ (unsigned int *) invalid_handler,/* 0x00AC 27 */ (unsigned int *) invalid_handler,/* 0x00B0 28 */ (unsigned int *) invalid_handler,/* 0x00B4 29 */ (unsigned int *) invalid_handler,/* 0x00B8 30 */ (unsigned int *) invalid_handler,/* 0x00BC 31 */ (unsigned int *) invalid_handler,/* 0x00C0 32 */ (unsigned int *) invalid_handler,/* 0x00C4 33 */ (unsigned int *) invalid_handler,/* 0x00C8 34 */ (unsigned int *) invalid_handler,/* 0x00CC 35 */ (unsigned int *) invalid_handler,/* 0x00D0 36 */ (unsigned int *) invalid_handler,/* 0x00D4 37 */ (unsigned int *) invalid_handler,/* 0x00D8 38 */ (unsigned int *) invalid_handler,/* 0x00DC 39 */ (unsigned int *) invalid_handler,/* 0x00E0 40 */ (unsigned int *) invalid_handler,/* 0x00E4 41 */ (unsigned int *) invalid_handler,/* 0x00E8 42 */ (unsigned int *) invalid_handler,/* 0x00EC 43 */ (unsigned int *) invalid_handler,/* 0x00F0 44 */ (unsigned int *) invalid_handler,/* 0x00F4 45 */ (unsigned int *) invalid_handler,/* 0x00F8 46 */ (unsigned int *) invalid_handler,/* 0x00FC 47 */ (unsigned int *) invalid_handler};extern unsigned int _DATA_BEGIN;extern unsigned int _DATA_END;extern unsigned int _DATAI_BEGIN;extern unsigned int _BSS_BEGIN;extern unsigned int _BSS_END;void nrf_init(void){uint32_t* bss_begin = (uint32_t*)&_BSS_BEGIN;uint32_t* bss_end = (uint32_t*)&_BSS_END;while(bss_begin < bss_end){*bss_begin = 0;bss_begin++;}uint32_t* data_begin = (uint32_t*)&_DATA_BEGIN;uint32_t* data_end = (uint32_t*)&_DATA_END;uint32_t* datai_begin = (uint32_t*)&_DATAI_BEGIN;while(data_begin < data_end){*data_begin = *datai_begin;data_begin++;datai_begin++;}main();}linker.ldCode:MEMORY{rom (rx) : ORIGIN = 0x00000000, LENGTH = 512Kram (rwx) : ORIGIN = 0x20000000, LENGTH = 96K /* Leave 32K for stack*/stack(rwx) : ORIGIN = 0x20017ff8, LENGTH = 0K}SECTIONS{.nvic_vector : /* Interrupt vector */{*(.nvic_vector)} >rom. = ALIGN(8);.text : /* Code run from flash*/{*(.text)*(.text.*)*(.rodata)*(.rodata.*)} >rom. = ALIGN(8);_DATAI_BEGIN = LOADADDR(.data);.data :{_DATA_BEGIN = .;*(.data)*(.data.*)_DATA_END = .;} >ram AT>rom. = ALIGN(8);.heap :{_HEAP = .;} >ram. = ALIGN(8);.stack :{_STACKTOP = .;} >stack. = ALIGN(8);.bss :{_BSS_BEGIN = .;*(.bss)*(COMMON)_BSS_END = .;} >ram. = ALIGN(8);}makefileCode:# This makefile is made to work with the toolchain downloadable at https://launchpad.net/gcc-arm-embeddedCC = arm-none-eabi-gccLD = arm-none-eabi-gccSIZE = arm-none-eabi-sizeOBJCOPY = arm-none-eabi-objcopyCFLAGS = -Os -I. -I./ext_include -fno-common -ffunction-sections -ffreestanding -mabi=aapcs -mthumb -mcpu=cortex-m4 -specs=nano.specs -Wall -Winline -fstack-usage -mfloat-abi=hard -mfpu=fpv4-sp-d16 -fno-strict-aliasingASMFLAGS = -S -fverbose-asmLDFLAGS = -mcpu=cortex-m4 -mthumb -nostartfiles -mabi=aapcs -mfloat-abi=hard -mfpu=fpv4-sp-d16 -specs=nano.specsOBJ = init.o main.oASMS = init.s main.sall: main.bin$(OBJ): %.o: %.c$(CC) -c $(CFLAGS) $< -o $@main.bin: $(OBJ) $(LIBS)$(LD) -Tlinker.ld $(LDFLAGS) -o main.elf $^ -lm$(OBJCOPY) -Obinary --remove-section=.ARM* --remove-section=*bss* main.elf main.bin$(SIZE) main.elfreset:nrfjprog -f nrf52 -rflash: main.binnrfjprog -f nrf52 --program main_full.bin --chiperase -r#flash_ocd: main.elf#openocd <something>stack:cat *.susections:arm-none-eabi-objdump -h main.elfsyms:arm-none-eabi-objdump -t main.elf%.s: %.c $(DEPS)$(CC) -c -o $@ $< $(CFLAGS) $(ASMFLAGS)asm: $(ASMS)clean:rm *.oI think that's all, except the usual cmsis* core* header files by ARM, and nrf52833.h and system_nrf52833.h by Nordic Semi.Setting up "bare toolchain"shouldbe fundamentally easy, but it is difficult because of secret information and obfuscation. By just cutting out unnecessary parts (for example: autogenerated startup files and linker scripts) makes it more understandable, until at some point the ends just meet and you are able to do it by providing everything (except the compiler itself, of course). It's quite revealing this is all copy-pasta from my earlier STM32H7 projects and it was running quickly exactly because I did not try to do anything differently (well, first I tried, and it did not lead anywhere.)But I think my example should be simple/small enough that you can actually go through every line and understand what it does, no?

author: uer166
author_rank: Super Contributor
timestamp: June 05, 2022, 07:30:57 am
content: A bit of an A-ha! moment, turns out I was linking the ARM pre-compiled libraries (GNU\ Arm\ Embedded\ Toolchain/10\ 2021.10/arm-none-eabi/lib/) instead of the Thumb ones (GNU\ Arm\ Embedded\ Toolchain/10\ 2021.10/arm-none-eabi/lib/thumb/v7e-m/nofp/).Of course the solution is easy, but to fix it took figuring out what exact instruction was faulting, and after assembling it it in an online assembler realizing that it is garbage unless it's set to ARM mode. It didn't help that the crt0.o was Thumb (works fine), but it was calling memset(), which was ARM (not fine). Cool learning experience..I'm eternally grateful for some Makefile examples, the next step was organizing it all into something that resembles a dev environment more.

author: Doctorandus_P
author_rank: Super Contributor
timestamp: June 16, 2022, 05:16:24 pm
content: As said before RF connections are never very reliable.Especially when moving around you could easily bump into some noise source that swamps your RF gadget.Effects can be mitigated and controlled up to some point with careful software design.For example, some of the RF chips have a quite fine grained Tx signal strength control and Rx signal level meters built in, and these could be used to monitor the quality of the connection.Directional antenna's may also help to reduce the effect of external noise sources.Both robustness against packet loss and alerting the user when a packet is lost also help in improving reliability.And it should always have some fail safe method build in for when the RF connection does die.Using a secondary backup set of RF transceivers in another frequency band (900MHz?) can add some extra reliability. both against RF disturbances and against mechanical failures such as broken of antenna's.There are some open sourced projects for RF controlled skateboards, and some of them have made it into (semi?) commercial products.