Author Topic: Reliable low-range wireless-enabled MCU/hardware/stack suggestions  (Read 3258 times)

0 Members and 1 Guest are viewing this topic.

Online uer166Topic starter

  • Frequent Contributor
  • **
  • Posts: 893
  • Country: us
Re: Reliable low-range wireless-enabled MCU/hardware/stack suggestions
« Reply #25 on: May 29, 2022, 07:08:24 am »
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.

Yeah 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 works
  • Attempt 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 been really handy 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)..
 

Offline jeremy

  • Super Contributor
  • ***
  • Posts: 1079
  • Country: au
Re: Reliable low-range wireless-enabled MCU/hardware/stack suggestions
« Reply #26 on: May 29, 2022, 07:23:49 am »
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.
 

Online Siwastaja

  • Super Contributor
  • ***
  • Posts: 8175
  • Country: fi
Re: Reliable low-range wireless-enabled MCU/hardware/stack suggestions
« Reply #27 on: May 29, 2022, 07:46:08 am »
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 is actually listening 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: [Select]
#ifdef SCOPE_OUTPUT
NRF_GPIOTE->CONFIG[1] = GPIOTE_TASK | GPIOTE_PIN(0,28) | GPIOTE_TOGGLE | GPIOTE_INITIAL(0);
NRF_PPI->CH[10].TEP = (uint32_t)&NRF_GPIOTE->TASKS_SET[1];
NRF_PPI->CH[11].TEP = (uint32_t)&NRF_GPIOTE->TASKS_CLR[1];
NRF_PPI->CH[10].EEP = (uint32_t)&NRF_RADIO->EVENTS_READY;
NRF_PPI->CH[11].EEP = (uint32_t)&NRF_RADIO->EVENTS_DISABLED;
NRF_PPI->CHENSET = 0b11UL<<10;


NRF_GPIOTE->CONFIG[2] = GPIOTE_TASK | GPIOTE_PIN(0, 3) | GPIOTE_TOGGLE | GPIOTE_INITIAL(0);
NRF_PPI->CH[12].TEP = (uint32_t)&NRF_GPIOTE->TASKS_SET[2];
NRF_PPI->CH[13].TEP = (uint32_t)&NRF_GPIOTE->TASKS_CLR[2];
NRF_PPI->CH[12].EEP = (uint32_t)&NRF_RADIO->EVENTS_ADDRESS;
NRF_PPI->CH[13].EEP = (uint32_t)&NRF_RADIO->EVENTS_END;
NRF_PPI->CHENSET = 0b11UL<<12;
#endif


... and my helpers on which this code relies on:

Code: [Select]
// 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[idx]; _tmp_ &= ~(0b1111UL<<0); _tmp_ |= 3UL<<2; (NRF_ ## port)->PIN_CNF[idx] = _tmp_; }while(0)
#define IO_TO_GPI(port, idx) do{ uint32_t _tmp_ = (NRF_ ## port)->PIN_CNF[idx]; _tmp_ &= ~(0b1111UL<<0); (NRF_ ## port)->PIN_CNF[idx] = _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[idx]; _tmp_ |= 1UL<<1; (NRF_ ## port)->PIN_CNF[idx] = _tmp_; }while(0)
#define IO_PULLUP_ON(port, idx) do{ uint32_t _tmp_ = (NRF_ ## port)->PIN_CNF[idx]; _tmp_ &= ~(0b11UL<<2); _tmp_ |= 3UL<<2; (NRF_ ## port)->PIN_CNF[idx] = _tmp_; }while(0)
#define IO_PULLDOWN_ON(port, idx) do{ uint32_t _tmp_ = (NRF_ ## port)->PIN_CNF[idx]; _tmp_ &= ~(0b11UL<<2); _tmp_ |= 1UL<<2; (NRF_ ## port)->PIN_CNF[idx] = _tmp_; }while(0)
#define IO_PULLUPDOWN_OFF(port, idx) do{ uint32_t _tmp_ = (NRF_ ## port)->PIN_CNF[idx]; _tmp_ &= ~(0b11UL<<2); (NRF_ ## port)->PIN_CNF[idx] = _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.
« Last Edit: May 29, 2022, 07:50:07 am by Siwastaja »
 
The following users thanked this post: uer166

Online uer166Topic starter

  • Frequent Contributor
  • **
  • Posts: 893
  • Country: us
Re: Reliable low-range wireless-enabled MCU/hardware/stack suggestions
« Reply #28 on: June 05, 2022, 12:19:25 am »
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: [Select]
$ ../openocd/bin/openocd.exe -f interface/stlink.cfg -f target/nrf52.cfg -c init -c "nrf5 mass_erase" -c "program image.elf verify" -c reset
xPack OpenOCD x86_64 Open On-Chip Debugger 0.11.0+dev (2022-03-25-17:32)
Licensed under GNU GPL v2
For bug reports, read
        http://openocd.org/doc/doxygen/bugs.html
Info : 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/SWD

nRF52 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 access
the CTRL-AP so 'nrf52_recover' command will not work.
Do not enable UICR APPROTECT.

Info : clock speed 1000 kHz
Info : STLINK V2J29S7 (API v2) VID:PID 0483:3748
Info : Target voltage: 2.578525
Info : [nrf52.cpu] Cortex-M4 r0p1 processor detected
Info : [nrf52.cpu] target has 6 breakpoints, 4 watchpoints
Info : starting gdb server for nrf52.cpu on 3333
Info : Listening on port 3333 for gdb connections
Info : nRF52811-QFAA(build code: A0) 192kB Flash, 24kB RAM
Info : Mass erase completed.
target halted due to debug-request, current mode: Thread
xPSR: 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 code
  • ARM CMSIS since the MDK stuff needs core_cm4.h
  • GNU Arm Embedded Toolchain for compilers/linkers/GDB

I'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: [Select]
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.
 

Offline cv007

  • Frequent Contributor
  • **
  • Posts: 828
Re: Reliable low-range wireless-enabled MCU/hardware/stack suggestions
« Reply #29 on: June 05, 2022, 03:09:15 am »
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/xKW38hEor
This 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.
 

Online uer166Topic starter

  • Frequent Contributor
  • **
  • Posts: 893
  • Country: us
Re: Reliable low-range wireless-enabled MCU/hardware/stack suggestions
« Reply #30 on: June 05, 2022, 03:23:08 am »
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 has one USART, and generally just lacking in peripherals, so I may need to figure out something else.
 

Online uer166Topic starter

  • Frequent Contributor
  • **
  • Posts: 893
  • Country: us
Re: Reliable low-range wireless-enabled MCU/hardware/stack suggestions
« Reply #31 on: June 05, 2022, 04:59:17 am »
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-called

As far as I can tell I am linking with thumb (which was the issue for one of the posters in Nordic forum):
Code: [Select]
/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: [Select]
/* 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[17] = 0x00000001;
  NRF_P0->PIN_CNF[18] = 0x00000001;
  NRF_P0->PIN_CNF[19] = 0x00000001;
  NRF_P0->PIN_CNF[20] = 0x00000001;
  while(1)
  {
    asm("nop");
  }
}
« Last Edit: June 05, 2022, 05:01:16 am by uer166 »
 

Offline cv007

  • Frequent Contributor
  • **
  • Posts: 828
Re: Reliable low-range wireless-enabled MCU/hardware/stack suggestions
« Reply #32 on: June 05, 2022, 06:26:18 am »
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/YM9oxo9Ka
should work for an 811 just the same as an 810.
« Last Edit: June 05, 2022, 06:40:14 am by cv007 »
 
The following users thanked this post: uer166

Online uer166Topic starter

  • Frequent Contributor
  • **
  • Posts: 893
  • Country: us
Re: Reliable low-range wireless-enabled MCU/hardware/stack suggestions
« Reply #33 on: June 05, 2022, 07:02:00 am »
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: [Select]
Breakpoint 1, SystemInit () at main.c:10
warning: Source file is more recent than executable.
10        asm("nop");
(gdb) step
halted: PC: 0x00000306
11        asm("push {R3}");
(gdb) step
halted: PC: 0x00000308
13        asm("ADD R1, R1, R1");
(gdb) step
halted: PC: 0x0000030a
halted: PC: 0x0000030c
halted: PC: 0x0000030e
halted: PC: 0x000002d6
Reset_Handler () at gcc_startup_nrf52811.S:284
284         bl __START
(gdb) step
halted: PC: 0x00000248



Program received signal SIGINT, Interrupt.
HardFault_Handler () at gcc_startup_nrf52811.S:304
304         b       .
(gdb) halted: PC: 0x000002ee
halted: PC: 0x000002ee

I'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  |O |O |O
 

Online Siwastaja

  • Super Contributor
  • ***
  • Posts: 8175
  • Country: fi
Re: Reliable low-range wireless-enabled MCU/hardware/stack suggestions
« Reply #34 on: June 05, 2022, 07:18:05 am »
Try this: it's for nRF52833 so minor modifications of memory addresses etc. might be needed, but anyways:

main.c
Code: [Select]
#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] != 0)
{
NRF_UART0->TXD = buf[0];
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.h
Code: [Select]
/*
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[idx]; _tmp_ |= 1UL<<1; (NRF_ ## port)->PIN_CNF[idx] = _tmp_; }while(0)
#define IO_PULLUP_ON(port, idx) do{ uint32_t _tmp_ = (NRF_ ## port)->PIN_CNF[idx]; _tmp_ &= ~(0b11UL<<2); _tmp_ |= 3UL<<2; (NRF_ ## port)->PIN_CNF[idx] = _tmp_; }while(0)
#define IO_PULLDOWN_ON(port, idx) do{ uint32_t _tmp_ = (NRF_ ## port)->PIN_CNF[idx]; _tmp_ &= ~(0b11UL<<2); _tmp_ |= 1UL<<2; (NRF_ ## port)->PIN_CNF[idx] = _tmp_; }while(0)
#define IO_PULLUPDOWN_OFF(port, idx) do{ uint32_t _tmp_ = (NRF_ ## port)->PIN_CNF[idx]; _tmp_ &= ~(0b11UL<<2); (NRF_ ## port)->PIN_CNF[idx] = _tmp_; }while(0)



init.c
Code: [Select]
/*
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 loops
void 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[FULL_VECTOR_TBL_LEN] __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.ld
Code: [Select]
MEMORY
{

  rom (rx)   : ORIGIN = 0x00000000, LENGTH = 512K
  ram (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);



makefile
Code: [Select]
# This makefile is made to work with the toolchain downloadable at https://launchpad.net/gcc-arm-embedded

CC = arm-none-eabi-gcc
LD = arm-none-eabi-gcc
SIZE = arm-none-eabi-size
OBJCOPY = arm-none-eabi-objcopy

CFLAGS = -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-aliasing
ASMFLAGS = -S -fverbose-asm
LDFLAGS = -mcpu=cortex-m4 -mthumb -nostartfiles -mabi=aapcs -mfloat-abi=hard -mfpu=fpv4-sp-d16 -specs=nano.specs

OBJ = init.o main.o
ASMS = init.s main.s

all: 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.elf

reset:
nrfjprog -f nrf52 -r

flash:  main.bin
nrfjprog -f nrf52 --program main_full.bin --chiperase -r

#flash_ocd: main.elf
# openocd <something>

stack:
cat *.su

sections:
arm-none-eabi-objdump -h main.elf

syms:
arm-none-eabi-objdump -t main.elf

%.s: %.c $(DEPS)
$(CC) -c -o $@ $< $(CFLAGS) $(ASMFLAGS)

asm: $(ASMS)

clean:
rm *.o


I 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" should be 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?
« Last Edit: June 05, 2022, 07:24:19 am by Siwastaja »
 
The following users thanked this post: uer166

Online uer166Topic starter

  • Frequent Contributor
  • **
  • Posts: 893
  • Country: us
Re: Reliable low-range wireless-enabled MCU/hardware/stack suggestions
« Reply #35 on: June 05, 2022, 07:30:57 am »
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.
 

Offline Doctorandus_P

  • Super Contributor
  • ***
  • Posts: 3365
  • Country: nl
Re: Reliable low-range wireless-enabled MCU/hardware/stack suggestions
« Reply #36 on: June 16, 2022, 05:16:24 pm »
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.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf