cancel
Showing results for 
Search instead for 
Did you mean: 

PWM Generation without using the PWM Mode of timers

SRama.2
Associate

Hi everyone. As the title suggests this might come across as an odd request. Basically I have been given a fully completed board with the microcontroller already placed on it.

I was asked to use it to generate PWM's from it and control a full bridge circuit with four MOSFETs. After some research, I figured out that the easiest way is to use the method described in the manual for generating complementary PWM's with dead time.

But then I ran into an issue. To generate the PWM's I use the TIM1 CH1 and CH1N channels. I understand that, I can get the PWM signals generated by this timer from a few output pins on the microcontroller. But unfortunately the board is designed in such a way that the outputs from these complementary channel pins are not connected to corresponding complementary MOSFETs in my circuit. So I cannot simply use the inbuilt PWM generation capabilities. So here are my questions,

  1. Are there any super obvious workarounds for this problem that are skipping my mind or I just cannot think off?
  2. How do I go about solving this and what would be the most efficient? Here were some of the ideas I could think off or I got from the internet
  • Ignore the PWM capabilities but just read the timer count values to manually generate PWM signals through a GPIO? Even for a beginner like me, this seems not very efficient. And I Ifeel like it might not work for some reason that I dont know yet.
    • I read somewhere else that I could fire interrupts at specific instances and kind of redirect the PWM signal to a GPIO pin. (https://electronics.stackexchange.com/questions/115946/how-do-i-redirect-timer-output-for-stm32f10x-to-a-given-gpio-pin) But I also read that using interrupts is also not particularly efficient
    • Somehow configure like two timers. One timer measures the dead time and at the end, triggers the other timer that generates the PWM and it triggers the dead time timer again. This would be super convenient but I am yet to look up whether this is even possible to do.

To summarize, this question is light on code because it is only the first solution that I have written the code for and I have not gotten a chance to see if it will work. I was hoping there was some way to fix this that I dont quite know about.

Any help is much appreciated 🙂

PS - I am still rather new to hardware programming. So please go easy on me if I am misusing some terms or my ideas wont work. xD

9 REPLIES 9
S.Ma
Principal

Short the right pins with the wrong ones. Then keep the unneeded ones as input.

Don't toggle the pins by SW, you will get jitter caused by higher priorty interrupts when code is running.

Use timer-triggered DMA from memory to GPIO.

But it's probably better to redesign the hardware in the proper way.

JW

Piranha
Chief II

Electronic engineers have not done their job right. The board is flawed and must be redesigned!

S.Ma
Principal

Agreed, but by hacking the board with shorting pins enables progress of HW debug the V1 board and minimize further reworks of V2.

Exploit as much as possible with minimal effort V1 board to clear as many issues before respin.

TFlac
Associate III

Technically speaking you should be able to do anything with a Microcontroller. The mere fact that the controller is hampering this effort is surprising to me. Yes, I am new to this new way of programming, super high level HAL abstracts that hide the lower level operation. As I said I am new to this higher level and think getting to know the LL (low level) drivers will be advantages in the long run. Back in the 1980s we had to learn and know what every register did, we programmed using ASSEMBLY language. The things you could do with a MCU were unlimited because we design at MACHINE hardware level.

As I proceed with my new designs I will make it my effort to learn as much as possible of the mechanics of the processor and LL design flow. The 6502 and 8051 processor ruled the world with lower level ASSEMBLY code for 50 years and is still in use. The ARM core is now the new hot topic today so we must move forward, but not too far from the hardware mechanics of the processor.

The generation of programmer and their background is evolving. SW Tools like compilers improved so that assembler is avoided at minimum penalty over C.

I think here we are talking about a lack of HW crossbar mux on the alternate function pins (SmartIO-like feature) which sometime enables pin hungry peripherals to be useable in smaller packages / cost.

As HD139139 already said, learn C and leave assembly for a few specific parts of code.

Making functions and calling them is also an abstraction. I bet you were also doing this in assembly on those 8-bitters. 🙂 But the more complex system you make, the more abstraction layers and splitting into modules you need. There is nothing wrong with an abstraction in itself. The problem is that HAL is a very bad implementation of it.

I don't see a big benefit of learning LL library. It's mostly the same register programming, but you have to learn two sets of naming the same things and introduce one more layer of potential bugs. My approach is to write my own high level "HAL" based on direct register programming in C.

I'm curious, do you have a specific speak for itself source code extract example of modified HAL vs the initial HAL?

Thanks!

That's why I was putting HAL inside quotation marks - my drivers are not based on HAL and doesn't use any of ST's code. Probably this can be a good example (for STM32F7):

static size_t SectorIndex_(void *pMem)
{
	size_t iSector;
	uintptr_t nbOffset = (uintptr_t)pMem - FLASHAXI_BASE;
 
	if (nbOffset < 0x20000) {
		iSector = nbOffset / 0x8000;
	} else if (nbOffset < 0x40000) {
		iSector = 4;
	} else {
		iSector = nbOffset / 0x40000 + 4;
	}
	return iSector;
}
 
res_t DRV_FLASH_EnsureErased(void *pMem, size_t nbMem)
{
	if ((pMem < (void*)FLASHAXI_BASE) || ((pMem + nbMem - 1) > (void*)FLASH_END)) {
		return E_INVALID;
	}
 
	res_t res = 0;
 
	for (volatile uint64_t *p = pMem; (void*)p < (pMem + nbMem); ++p) {
		if (*p != FLASH_MEMORY_STATE_ERASED) {
			SectorErase_(SectorIndex_((void*)p));
			SCB_InvalidateDCache_by_Addr(pMem, nbMem);
			++res;
		}
	}
	return res;
}

SectorErase_() is nothing special - takes sector index. And in this case uint64_t is compiled with LDM instruction and really is twice faster than uint32_t.

DRV_FLASH_EnsureErased() ensures that a memory region is erased without doing unnecessary erase operations. And, when no actual erase is required, it does that verification lightning fast. The existence of such a function enables "EEPROM emulation" to be built on different, simpler and much more robust operating principles compared to ST's one. I'm putting "EEPROM emulation" again inside quotation marks, because my implementation is not based on ST's one and doesn't even emulate EEPROM principles.