STM32F1 Hardware Nodes See also arm.txt Entry: USB disconnect Date: Thu Sep 5 21:46:34 EDT 2019 Let's try to get that USB pullup resistor off. EDIT: It is R11 on the recent batch of bluepill boards. Easy to check by plugging it into one of the cheap USB hubs that has D+ D- easily accessible, and then just beeping it out. EDIT: R11 is the one that is connected to D+, but it is not the pullup. How to mod the board? Take off R10, and flip it over to the nearest GPIO which is B3. I hope that's not the LED. Nope that's C13. Dammit B3 is part of debug interface. B5 is the closest one. Ok that works. But it doesn't come back up after reset. https://community.st.com/s/question/0D50X00009XkaeVSAR/reenumerate-usb-stm32f107 STM32F4 usb can do a 'soft disconnect' OTG_FS_DCTL SDIS OTG_FS 28.5.2 Peripheral states EDIT: A11 (D-) and A12 (D+) are actually just on the pins. Currently I don't have a good solution for reset. I don't understand why it doesn't re-enumerate on reset. Also when I just replug the micro usb it doesn't re-enumerate ether. But that works in the other hub. And there reset also works. Odd, the back side ports of that amazon hub do work ok. So now it just needs a reset. Watchdog is probably simplest. Entry: Building the DHT11 boards Date: Sat Nov 9 11:01:35 EST 2019 EDIT: Why did I get stuck yesterday? I ended up at a point where I had to plug in a mechnaism that I did not test in isolation, in a system that is untested in isolation. It is good that I've developed some aversion to this. What is still necessary is to formulate a mental model for it as well. The EXT is easy to test. The next step is to make some simpler code that sets up the one-shot. Entry: dht11 Date: Mon Nov 11 09:19:24 EST 2019 Well it's doing _something_. EDIT: Ok, it works. Straightforward, as I thought. Splitting hw and logic seems to be a really good idea. Also makes it clear that the API between the two isn't clear until the logic is fully debugged. I.e. testing does need to happen on the actual hardware to shift some of those arbitrary decisions around. Entry: DHT22 install Date: Sun Nov 24 10:27:49 EST 2019 So do this only for "fixed" installs. Start with zoo? Maybe before any of that, find a way to properly physically mount a bluepill using screws on wood substrate. EDIT: Other time. Entry: Interrupt priorities Date: Thu Dec 26 14:49:08 CET 2019 I want TIMER and UART interrupts to arrive in the same handler to be able to order events. If one pre-empts the other, there is a race condition where a byte can arrive and at the same time a timeout can happen. I believe this can be solved by ensuring the same priority level for interrupts. That way the timer interrupt can be disabled in the UART ISR. See chapter 10: interrupts and events. Interrupt table: POS PRI ADDR TIM2 28 35 B0 USART1 37 44 D4 So by default, the TIM2 preempts the USART1, which is not what I want. However, if this is only using the upper 4 bits of an 8-bit priority, then the levels are the same: Both 35 and 44 are 2 after >>4. So let's assume for now that there is no pre-emption between the two handlers. Additionally, the code in libopencm3: void nvic_set_priority(uint8_t irqn, uint8_t priority) { /* code from lpc43xx/nvic.c -- this is quite a hack and alludes to the * negative interrupt numbers assigned to the system interrupts. better * handling would mean signed integers. */ if (irqn >= NVIC_IRQ_COUNT) { /* Cortex-M system interrupts */ SCS_SHPR((irqn & 0xF) - 4) = priority; } else { /* Device specific interrupts */ NVIC_IPR(irqn) = priority; } } http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0337e/Cihcbadd.html Interrupt Priority Registers Use the Interrupt Priority Registers to assign a priority from 0 to 255 to each of the available interrupts. 0 is the highest priority, and 255 is the lowest. The priority registers are stored with the Most Significant Bit (MSB) first. This means that if there are four bits of priority, the priority value is stored in bits [7:4] of the byte. However, if there are three bits of priority, the priority value is stored in bits [7:5] of the byte. This means that an application can work even if it does not know how many priorities are possible. The register address, access type, and Reset state are: Address 0xE000E400-0xE000E41F /** System Handler Priority 8 bits Registers, SHPR1/2/3. * Note: 12 8bit Registers */ #define SCS_SHPR(ipr_id) MMIO8(SCS_BASE + 0xD18 + (ipr_id)) /* NVIC_BASE + 0x220 (0xE000 E320 - 0xE000 E3FF): Reserved */ /** IPR: Interrupt Priority Registers * @note 240 8bit Registers * @@note 32 8bit Registers on CM0 */ #define NVIC_IPR(ipr_id) MMIO8(NVIC_BASE + 0x300 + \ (ipr_id)) #define NVIC_BASE (SCS_BASE + 0x0100) #define SCS_BASE (PPBI_BASE + 0xE000) #define PPBI_BASE (0xE0000000U) PPBI_BASE E0000000 SCS_BASE E000E000 NVIC_BASE E000E100 NVIC_IPR E000E400 + 0-239 Let's search online for nvic_set_priority() This has defines: include/libopencm3/stm32/f1/nvic.h #define NVIC_TIM2_IRQ 28 #define NVIC_USART1_IRQ 37 Let's just assert them? Entry: Blue Pill R10 Date: Thu Jan 16 10:04:23 CET 2020 https://coytbarringer.com/programming-stm32f103-blue-pill-using-usb-bootloader-platformio/ This says to change R10 from 10k Ohms to 1.5k Ohms to make USB work properly. Entry: Disabling application Date: Mon Jan 20 07:16:57 EST 2020 It's doing something I don't understand. Let's try not enabling interrupts maybe? The command is executed from the USB poll routine. EDIT: Reload works if I don't enable any interrupts. Once I enable timer it starts failing. I can't figure out how to turn off the damn interrupt. Everything works as long as I don't enable the timer. Odd. If peripheral reset doesn't work, what will? How to move this forward? Find out if assumptions are correct. I.e. make sure app is not started etc.. How bad do I want this? For one application I can probably use external reset. I just don't get it.. This is a time sink. Here's one thing to try: put the interrupt table and all handlers in RAM. That would for sure remove the case that it is jumping into Flash code. Maybe there is some interrupt that I'm not aware of? But then it should still have an issue when timer wasn't initialized. Something weird is going on. Maybe check errata? It has to be an interrupt, so list the entire interrupt table. (gdb) p/x *(vector_table_t*)0x8003000 $16 = {initial_sp_value = 0x20005000, reset = 0x8003941, nmi = 0x8003907, hard_fault = 0x8003905, memory_manage_fault = 0x8003905, bus_fault = 0x8003905, usage_fault = 0x8003905, reserved_x001c = {0x0, 0x0, 0x0, 0x0}, sv_call = 0x8003907, debug_monitor = 0x8003907, reserved_x0034 = 0x0, pend_sv = 0x8003907, systick = 0x8003907, irq = {0x8003905 , 0x80038d5, 0x8003905, 0x8003905, 0x8003905, 0x8003905, 0x8003905, 0x8003905, 0x8003905, 0x8003905, 0x8003885, 0x8003905 }} (gdb) p/x *(vector_table_t*)0x8000000 $17 = {initial_sp_value = 0x20002000, reset = 0x8000231, nmi = 0x80001f7, hard_fault = 0x80001f5, memory_manage_fault = 0x80001f5, bus_fault = 0x80001f5, usage_fault = 0x80001f5, reserved_x001c = {0x0, 0x0, 0x0, 0x0}, sv_call = 0x80001f7, debug_monitor = 0x80001f7, reserved_x0034 = 0x0, pend_sv = 0x80001f7, systick = 0x80001f7, irq = {0x80001f5 }} irq = {0x8003905 , 0x80038d5, 0x8003905, 0x8003905, 0x8003905, 0x8003905, 0x8003905, 0x8003905, 0x8003905, 0x8003905, 0x8003885, 0x8003905 }} (gdb) p/x (void*)tim2_isr $20 = 0x80038d4 (gdb) p/x (void*)usart1_isr $21 = 0x8003884 Yeah nothing surprising there. Maybe disable interrupts altogether? Or look at the flash write? I'm just guessing... Pick this up again if it is really necessary, otherwise work around it. UNRESOLVED Entry: STM reset Date: Mon Jan 20 10:02:36 EST 2020 1. Software reset doesn't work: hangs when erasing flash. Likely due to timer interrupt, though I can't figure out. 2. Power cycle is most robust. Use this for in-house dev. 3. Hardware reset can be made to work, but requires mod to blue-pill board to properly configure the USB pullup. Current firmware uses B5, but this is part of SPI so prob not a good idea. Entry: USB hack Date: Mon Jan 20 11:05:49 EST 2020 Driving D+ to low before usb init? https://amitesh-singh.github.io/stm32/2017/05/27/Overcoming-wrong-pullup-in-blue-pill.html Entry: I really want that OS Date: Tue Jan 21 04:46:29 EST 2020 Since the DMX box, I'm getting more convinced that separating HW and SW for my particular application domain isn't really that hard. Two things can make this a lot easier: - Write in CSP, and plug the portable part into a Linux hosted C program that ties into Erlang or Haskell test suite. - Since HW interface doesn't change often, use the existing 2nd stage loader functionality to reload code on the fly. Entry: That OS Date: Wed Jan 22 08:40:31 EST 2020 What is needed? In principle the interface between the OS layer and the application could be just C, but in practice this is quite hard to work with when modifying both at the same time, and having some updated and some not. So use some kind of "extend only" binairy interface. It would be a good exercise in doing so. Changing the interface would then require to update the OS layer for all devices. So, each device has: - gdbstub - a standard interface to host (USB slip) - A csp-style scheduler - Some HAL that is connected through cbuf "commands". Entry: That OS again Date: Thu Jan 23 08:04:20 EST 2020 Take another view: make something that can host a process. A process is code and a list of input/output channels. To reload a process, remove it from the scheduler, reflash its code, and restart. This mostly needs an allocator. Or, in first iteration, make sure that code fits in single blocks. Entry: Flash loader Date: Thu Jan 23 08:33:05 EST 2020 Let's look at the code I already had, and start to work this into CSP. I've been using lab_board.c as host. EDIT: see also host.c Current state of mind is too dull to be able to pull this off, so find a simpler thing to do. Entry: SPI DAC Date: Thu Jan 23 08:46:01 EST 2020 Let's build a CV converter. There are a couple of things that can be done with this later. It would test SPI as well. Entry: Device drivers Date: Fri Jan 24 09:04:58 EST 2020 With CSP library, decoupling hardware is going to be simpler. So start writing some device drivers for interrupt routines with buffer I/O. It's always been a problem, and it's always going to be finicky, so it would be good to have a working example at hand. Start with hw_csp_f103_spi.h Entry: dht11 / dht22 board Date: Fri Jan 24 10:32:34 EST 2020 Putting this into a separate cardboard box on the shelf labeled DHT11. The driver works, but to make these ready to use some more infrastructure is needed. Two avenues: - Plug a BP into a Ethernet<->USB bridge somehwere - Add BP<->BP connectivity First should probably be to integrate this into existing thermostat. Entry: BP<->BP Date: Fri Jan 24 10:38:08 EST 2020 I'm running into a couple of cases where it would be nice to have a cable that's a bit longer than USB, without having to go to Ethernet. The obvious choice is RS485. The DHT11 brings this to mind: a string of BPs all with local sensor nodes. This project is not urgent though, so I've boxed the DHT11. Entry: Lab board Date: Sat Jan 25 06:24:45 EST 2020 Let's continue on with lab board. I think that was able to do code reloads. Maybe it would be simpler to decouple this? I don't really need the code reload at this time. I just need serial comm. Let's start with c8 example and strip it down. EDIT: The idea is to be able to send messages over serial/RS485. Entry: interrupt driven tx Date: Sat Jan 25 07:56:29 EST 2020 In the isr, keep pushing out data from cbuf. If empty, disable the interrupt. To translate that into CSP signal flow, do the following: - If there are more characters to transmit, keep going. - When done, send a signal on the shared interrupt pipe EDIT: Ok got it working. Trick was to use both transmit ready and transmit done interrupts. Next step is probably to also do the packet decoding in the interrupt. Or maybe not. Let's stick to bytes. Entry: testing CSP Date: Sat Jan 25 11:35:31 EST 2020 - basic setup + USB receive task - byte receive For byte receive an interrupt queue is necessary. So start with that: single interrupt queue. For now just poll it. Later make it use WFI. Entry: 4.5MBaud Date: Sat Jan 25 20:12:47 EST 2020 works Entry: property based testing Date: Sun Jan 26 04:13:44 EST 2020 Close the loop: perform a transmission, do a checksum, see if it matches. Make those things easy to write. Entry: HAL Date: Sun Jan 26 07:02:38 EST 2020 So _input_ is currently going throug cbufs -> poll -> CSP. All interrupts are inputs. Network _output_ still needs platform-dependent functions. In principle these could be wrapped as macros. Entry: Why can't I just write into a task's buffer? Date: Sun Jan 26 07:04:36 EST 2020 Keeps coming back. Buffers aren't always the best way to represent data. EDIT: Coming back to this: the core idea is ownership. Shared mutable memory isn't a good idea, but if there is a concept of ownership then it might not be such a big deal. Channels can still transfer lazy buffers, e.g. callbacks or state machines that produce or consume data. Data on channels doesn't have to be "just bytes". The key is: - information transfer + syncrhonization - some kind of task structure with local execution context Entry: That OS Date: Sun Jan 26 09:27:58 EST 2020 So what I want is to be able to start an arbitrary task on a running uC. Problem is that there doesn't seem to be something like an "open" CSP application. E.g. suppose this: some uC is sitting there and I want to run a thermomenter interface on it. It seems to be almost impossible to just load the driver for that. It seems better to keep them stand alone: download bulk firmware on startup. So the idea definitely needs some more practical use to get a good idea of what would be useful. Entry: Rust Date: Sun Jan 26 12:28:40 EST 2020 https://ioprog.com/2019/09/03/rust-and-c-side-by-side-on-the-stm32f103c8t6-blue-pill-board/comment-page-1/ Entry: UART RS232 Date: Sun Jan 26 14:21:02 EST 2020 PC14 / PC15 Entry: Practical projects Date: Tue Feb 4 08:00:08 EST 2020 Improve thermometers. This probably requires RS485 to tuck away sensors. Note that the DHT11 can probably work with long wires too being a current signal. Maybe even audio cable. ( rs485 comm is what i find interesting, but the long dht11 wire is probably easier to implement. ) Entry: Makefile for uc_tools Date: Tue Feb 4 14:47:43 EST 2020 Might not be worth the trouble to create Makefiles. Can I make a trace of the build commands? Maybe this is a good target to convert to the Erlang redo. I also want to show this on a web page, e.g. some squares with output? Entry: Writing out a number of gpio bits at once Date: Mon May 11 12:09:17 EDT 2020 See RM 9.2 GPIO registers 9.2.4 Port output data register GPIOx_ODR 9.2.5 Port bit set/reset register GPIOx_BSRR The first one is direct write to all the port bits, the latter is slective set/reset. Entry: FSMC Date: Mon May 11 12:10:34 EDT 2020 Note that the STM32F1 also has an FSMC Entry: Fast I/O mode switching Date: Mon May 11 17:31:09 EDT 2020 I'm now starting to wonder if open drain output isn't already just supported: 9.2.1 Port configuration register low GPIOx_CRL If this is set to MODE=01 output, max 2MHz CNF=01 open drain 9.1.8 Output configuration Entry: 5V tolerant? Date: Mon May 11 18:19:07 EDT 2020 Which ports are 5V tolerant? Entry: Configuring SPI1 clock frequency? Date: Wed May 13 20:11:45 EDT 2020 I want to send out WS2812B protocol using SPI data. This needs a tunable SPI frequency, and my hw_ library was hard-coded to SPI_CR1_BAUDRATE_FPCLK_DIV_2 in CR1. It seems that BR slot in CR1 only allows deriving from PCLK. It's possible to use a timer when you clock it externally. I think I've seen that used like that. So is it ok to approximate? Entry: Bit-banging WS2812 Date: Thu May 14 17:17:18 EDT 2020 The idea was to do this interrupt-driven. But the bit times are actually quite small: 400ns is 2.5MHz This is not such a bright idea, since a pulse is only 28 machine cycles. To make this work it might be simplest to busy-wait in the ISR to send the first edge after 30 or 60 cycles. So SPI is really not such a bad idea. Entry: use boot pins? Date: Thu May 14 19:39:48 EDT 2020 BOOT0 is dedicated BOOT1 is PB2 BOOT1 BOOT0 x 0 main flash 0 1 system memory 1 1 embedded ram so BOOT1 can be used as application switch. I'm assuming it's the bottom one in the orientation of the silk screen. Entry: stm32f103c8 memory Date: Fri May 15 17:04:13 EDT 2020 STM says 64kB, but the board I have seems to be able to access words up to 0801FFFC Trying to acess 08020000 crashes. Entry: erase Date: Fri May 15 18:18:24 EDT 2020 Do interrupts need to be disabled to write to flash? I just don't get it. It hangs when I try to erase, and I think it has something to do with interrupts. https://stackoverflow.com/questions/3445598/does-the-cortex-m3-stm32f103-core-stall-during-a-flash-page-erase-because-the-fp That suggests to run ISRs from RAM. EDIT: When I don't turn on the interrupts, it works fine. So what the hell is going on here? Enable one at a time to see which one causes the problems. It's starting to look like the problem is with TIM2. If I change it to TIM4 everything just works. So it looks like this is a hardware issue. Entry: Timers Date: Sat May 16 12:52:47 EDT 2020 - Advanced-control timers: TIM1 TIM8 - General-purpose timers: TIM2 TIM3 TIM4 TIM5 - Basic timers: TIM6 TIM7 - General-purpose timers (XL-density only, 768kByte Flash and up) TIM9 TIM10 TIM11 TIM12 TIM13 TIM14 Entry: PWM audio Date: Mon May 25 19:05:26 EDT 2020 15.3.9 PWM mode I'm getting bad playback. I think this needs preload enabled: OCxPE in TIMx_CCMRx. Nope I have that configured. I'm doing something else wrong. Probably this: INLINE void hw_clockgen_duty(struct hw_clockgen c, uint32_t value) { /* Copied from timer_common.all.c to allow inline. */ // timer_set_oc_value(c.tim, c.chan, c.duty); switch (c.chan) { case TIM_OC1: TIM_CCR1(c.tim) = value; break; case TIM_OC2: TIM_CCR2(c.tim) = value; break; case TIM_OC3: TIM_CCR3(c.tim) = value; break; case TIM_OC4: TIM_CCR4(c.tim) = value; break; } } Shouldn't it use ARR? no it is TIMx_CCRx Entry: UART Date: Tue May 26 10:41:17 EDT 2020 I've been exclusive using USART1 for everything. Never needed more than one. Which one should be used for other operations? I might have actually started working on a multi uart serial port module. Working on blue pill which is medium density. PA2 USART2_TX PA3 USART2_RX PB10 USART3_TX PB11 USART3_RX Currently USART3 seems best because the other's pins are already used. Entry: Infrared decoder Date: Tue May 26 11:47:45 EDT 2020 How to build an infrared decoder? I see two ways: - EXTI + timestamps - EXTI + timeouts Preference goes to timestamps. Then the underlying code can be used to create a generic diff-encoded logic recorder first, which is useful for other things. Entry: Make it easier to patch the board Date: Fri May 29 19:07:34 EDT 2020 USBDP is at PA12 What is next to that on the BP? A15 But I probably tried that one already... It's also JTDI PB5 is actually fairly close. Entry: 5V tolerant input drawing current Date: Sun May 31 18:23:08 EDT 2020 I'm not sure what is going on, but a 5V tolerant input draws 110 uA out of the 5V supply. This is A4. Maybe it is just not 5V tolerant. It sits there at about 4V, which is a diode drop above 3v3. Ok it is in the 103 datasheet (not the RM). See note (2) in the pin definitions table. I guess this is just bad luck. A4 is 3v3 indeed. PA8-12 PB2 PB6-15 PC10-12 Entry: System reset Date: Mon Jun 1 16:27:09 EDT 2020 This doesn't work: SCB_AIRCR |= SCB_AIRCR_SYSRESETREQ; Use the watchdog instead. Entry: EXTI mapping Date: Mon Jun 1 21:43:51 EDT 2020 There are 15 EXTI lines, each can be mapped to ports A-E. The first 5 have dedicated interrupts: #define NVIC_EXTI0_IRQ 6 #define NVIC_EXTI1_IRQ 7 #define NVIC_EXTI2_IRQ 8 #define NVIC_EXTI3_IRQ 9 #define NVIC_EXTI4_IRQ 10 These are shared: #define NVIC_EXTI9_5_IRQ 23 #define NVIC_EXTI15_10_IRQ 23 Entry: Blue pill default pins Date: Mon Jun 1 21:48:42 EDT 2020 Start out with this if there are no other constraints. Create a go-to mapping. The ' are 5V tolerant. --- Base functionality: RS485 on UART1: 'A8 = DIR (1 = drive, 0 = read). 'A9 = TX 'A10 = RX (5V tolerant on STM32F103x8) BOOT1: 'PB2 usb pullup: B5 (usb pullup) USB: 'A12 D+ 'A11 D- SPI1: A7 MOSI A6 MISO A5 SCK A4 CS I2C1: 'B7 SDA 'B6 SCL --- For app: JUST IO / ADC: PC14 PC15 A0 ADC0 A1 ADC1 JUST IO (needs JTAG disable, which I can't figure out): B4 B3 A15 UART2: A2 TX A3 RX PWM: B0 B1 --- Peripheral or 5V io: SPI2: 'B15 MOSI 'B14 MISO 'B13 SCK 'B12 CS I2C2: 'B9 SDA 'B8 SCL UART3 (I2C2): 'B10 TX 'B11 RX Entry: Disable jtag but keep swd enabled? Date: Mon Jun 1 22:18:58 EDT 2020 31.4.1 SWJ debug port pins SWD JTAG PA13 SWDIO TMS PA14 SWCLK TCK PA15 - JTDI PB3 TRACESWO JTD0 PB4 - NJTRST On BP PA13,14 are on the SWD connector. The other 3 need to be enabled explicitly: https://community.st.com/s/question/0D50X00009XkZipSAF/stm32f103-pa15-as-gpio AFIO_MAPR Bits 26:24 SWJ_CFG[2:0] 010: JTAG-DP Disabled and SW-DP Enabled This doesn't work: /* Use the JTAG pins as I/O */ // Why is this not working? uint32_t mapr = AFIO_MAPR; mapr &= ~AFIO_MAPR_SWJ_MASK; mapr |= AFIO_MAPR_SWJ_CFG_JTAG_OFF_SW_ON; AFIO_MAPR = mapr; hw_gpio_config(GPIOA,15,HW_GPIO_CONFIG_OUTPUT); hw_gpio_config(GPIOB,3,HW_GPIO_CONFIG_OUTPUT); hw_gpio_config(GPIOB,4,HW_GPIO_CONFIG_OUTPUT); Someone else complained about it: https://community.st.com/s/question/0D50X00009XkZMmSAN/stm32f103-pb3-just-doesnt-work-as-gpio I can't figure this out. So don't use them. Entry: can't get i2c to work Date: Thu Jun 11 00:34:05 EDT 2020 it hangs here: while (!(I2C_SR1(i2c) & I2C_SR1_ADDR)); If I replace those waits with: hw_busywait_us(sleep_us); Then it does goes through with transmitting. Does it need to enable these interrupts? void i2c_enable_interrupt(uint32_t i2c, uint32_t interrupt) { I2C_CR2(i2c) |= interrupt; } ITEVTEN event interrupt enable I2C_CR2_ITEVTEN That didn't do anything EDIT: Looks like it is a bug. SR1 as AF (acknowledge failure) set. Entry: Cortex M saving registers in interrupt Date: Sun Jun 14 14:28:02 EDT 2020 A normal C function respects the calling convention: https://stackoverflow.com/questions/261419/what-registers-to-save-in-the-arm-c-calling-convention Cortex M interrupts will allso do this: Cortex M3 will push R0-R3,R12,LR,PC,xPSR Cortex M4,M7 can (optionally?) store additional floating point state. Together with a special LR value, this allows regular C functions to be used as interrupt handlers. EDIT: 0xFFFFFFF9 is a special value placed in the LR when entering an exception (known as EXC_RETURN https://community.arm.com/developer/ip-products/system/f/embedded-forum/44331/how-to-get-link-register-when-it-has-0xfffffff9-in-isr Entry: USB driver hickup Date: Sun Jun 21 16:04:07 EDT 2020 It is sitting in the poll routine for 37-40 ms. Let's have a look at that. ~/exo/libopencm3/ lib/stm32/common/st_usbfs_core.c include/libopencm3/stm32/common/st_usbfs_v1.h include/libopencm3/stm32/common/st_usbfs_common.h Is there any place where this could be looping? st_usbfs_poll() has no loops so in one of the fuctions? st_usbfs_ep_read_packet(dev, ep, &dev->control_state.req, 8); st_usbfs_copy_from_pm() ? I don't believe this would be the issue. Maybe it is hanging in one of the interrupts? Let's add counters. Entry: high word fixed point Date: Mon Jun 22 23:53:24 EDT 2020 UMULL UMLAL SMULL SMLAL U unsigned S singed MUL multiply MLA multiply accumulate L long 32x32 -> 64 but typicall used as 32x32->32 and keeping only the high word. Entry: try not using global variables Date: Sun Jul 5 14:35:34 EDT 2020 It's better to create a single giant struct and pass it around from function to function. Otherwise pointers will need to be stored for every function that references the global variable, while for struct members the origin is in a register, and the rest can be referenced. Entry: TIMx_ARR Date: Tue Jul 7 23:40:31 EDT 2020 I might not understand this properly... What I want is to update the _oc register. TIM_CCR1(c.tim) = val OC1PE Entry: swtimer.h Date: Thu Jul 30 16:18:23 EDT 2020 Basic functionality seems ok. TODO is hardware integration, most importantly, proper synchronized update of the data structure, e.g. disable timer interrupt, modify struct and timer config, enable timer interrupt. Entry: load a binary using openocd Date: Sat Aug 22 12:53:07 EDT 2020 Use the telnet port 4444: https://dev.to/aaronc81/flashing-your-pinetime-using-an-st-link-and-openocd-54dd tom@zora:~$ telnet localhost 4444 Trying ::1... Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. Open On-Chip Debugger > reset halt target halted due to debug-request, current mode: Thread xPSR: 0x01000000 pc: 0x08000230 msp: 0x20002000 > targets TargetName Type Endian TapName State -- ------------------ ---------- ------ ------------------ ------------ 0* stm32f103c8t6.cpu hla_target little stm32f103c8t6.cpu halted > flash banks #0 : stm32f103c8t6.flash (stm32f1x) at 0x08000000, size 0x00010000, buswidth 0, chipwidth 0 > flash erase_address 0x08004000 0xC000 erased address 0x08004000 (length 49152) in 1.139112s (42.138 KiB/s) > program /tmp/dmx_nano.x8a.f103.fw 0x08004000 verify EDIT: It seems much more convenient to just wrap the bin into an elf with objcopy. That way gdb can flash it, and a gdbstub can be used as well. Entry: Disassembling raw file Date: Sat Aug 22 18:03:23 EDT 2020 arm and thumb instructin sets: arm-none-eabi-objdump -b binary -marm -D test.bin arm-none-eabi-objdump -b binary -marm -Mforce-thumb -D test.bin Entry: Persistent write Date: Wed Aug 26 09:28:23 EDT 2020 What I want: create a data structure in Flash that doesn't need parsing, and create it in C. Start with a simple flat structure with strings.