Stm32 PWM sampling - timer

I have a timer set up in the cube to make a PWM... Just setting ARR and CCR to different values.
I'm using the callback functions for both events that HAL set up for me, I think one is for the CCR compare event and the other is for the ARR compare event.
Anyway, in both of those I'm toggling a GPIO port like this:
GPIOC->ODR = foo;
Anyway, I want to sample the values of 3 ADC1 channels during the high pulse, but I'm not sure how to do that accurately. I'm using DMA in circular mode with the ADC1 right now.
I don't want to sample immediately after setting the pins, because there's propagation delay, noise, etc.
So, I want to:
Set the pins, wait a very short and constant amount of time, sample all the channels and then do some math on the results.
This is for a Bldc motor controller, by the way... Im trying to sample the BEMF on the positive side of the PWM drive signal, and I'm driving it at 18khz, 5% duty cycle, so my pulse lasts for 2.7us.
I'm not sure how to handle or debug this because it's so timing related and I need the motor to deliver the signal that I'm using... If the motor isn't spinning, then there's no feedback signal to work on. It sure seems like I'm trying to do too much in the timer ISRs, though.
Sorry I can't post any code right now... Im at the grocery store, but I'll put some up when I get back.

Related

stm32: PWM generator with 1/20 pulses

I'm struggeling on setting up a STM32-F429ZI MCU (Nucleo 144 board) to generate following PWM pattern:
First channel with a variable frequency and 50% duty cycle - at least I've got this working -
Second channel giving a pulse with each 20th pulse of channel 1.
This is not primary a coding problem but a understanding problem of timer settings i guess (working with STM32CubeIDE). I would bet there is real simple solution...
I Think there is no way to do this with only 1 timer?
I'm pleased for any suggestion...
I already tried with TIM2 as clock source for TIM3 and 4 but couldn't manage to make them synchonize.
For better illustration of what I want to do:
I't not sure, if it could be done with two timer synchronization (the pitfall is variable frequency of the first timer). But you can use single timer+DMA to rewrite configuration of the second channel:
Create in-memory array of 20 values, where one value enables the second channel and other 19 disables it
Setup DMA to trigger on the timer update and to move data from the array to CCMRx (or CCRx) register. Of cource, DMA should be in circular mode

DC Motor speed and direction with PWM PSoC

I need to be able to change the direction and speed of a small dc motor using an PSoC LP5 and a L293D. The motor that was used is one of these: https://www.elecrow.com/dc-toy-hobby-motor-130-size-p-265.html. I was able to change the direction without PWM by changing the inputs, this gave me the following table.
But then I also had to change the speed. The schematics for this project can be found below. The PWM period has been set to 1000.
My code looks like this:
int main(void)
{
PWM_1_Start();
for(;;)
{
DIRECTION_Write(0);
PWM_1_WriteCompare(400);
CyDelay(2000);
// 2 seconds clockwise low speed
PWM_1_WriteCompare(0);
CyDelay(2000);
// 1 second nothing
DIRECTION_Write(1);
PWM_1_WriteCompare(400);
CyDelay(2000);
// 2 seconds counter-clockwise low speed
PWM_1_WriteCompare(0);
CyDelay(2000);
// 1 second nothing
}
}
The motor now only turns counter-clockwise, then stops for 5ish seconds en does the same again. I've tried other combinations such as also using SPEED_Write, but didn't get the result I wanted.
Any help is appreciated, thanks in advance :)
I've done exact thing with an L298, which I think is esentially the same as an L293. It's easiest to switch the EN pin and not the IN# pins. Move your PWM to EN1, and then control the direction with IN1 and IN2. When IN1 is 0 and IN2 is 1, the motor moves CCW. When the pins are reversed, it moves in the other direction.
With a PSoC5 you can control both IN# pins with 1 signal. Add a 1-bit Control Register to your schematic and connect it to 2 pin components Then put a NOT gate between the second Gpio and the control register. Then you can write to the Control Register, and both Gpios will be toggled at the same time, but will always be the opposite of each other.

MSP432 Interrupt With Encoder Count

I am using a MSP432 for a project and I would like to know how to generate a interrupt when a incremental encoder has reached a specified count. The interrupt should stop a motor from moving in a particular direction.
Background: I'm using a incremental encoder to control a brush motor. As the brush motor moves left or right, it is mechanically connected to a incremental encoder that counts pulses or "clicks". The incremental encoder is effectively controlling the limit of motion of the motor. Ie, if the encoder reads 20 pulses in the right direction, the motor should stop. My project has two modes of operation controlled by a switch-case statement. The first is a routine mode, and the second is a mode where a user can control the motor with a joystick. Regardless of whichever mode the program is in, the motor should stop when the limit of motion has been reached.
Psedo Code:
Case: Routine Button Mode
{
// Motor executes right, left, right movement routine
digitalWrite(directionMotor,RIGHT); // telling motor what direction to go
analogWrite(pwm_motor2,60); // telling motor to activate at 60% PWM
if(encoder_count == Motion_Limit)
analogWrite(pwm_motor,0); // tell motor to stop
// change direction
digitalWrite(directionMotor,LEFT); // telling motor what direction to go
analogWrite(pwm_motor2,60); // telling motor to activate at 60% PWM
}
Case: Joystick_Control
{
while(analogRead<10) // Joystick is pushed to the left
{
digitalWrite(directionMotor,LEFT); // telling motor what direction to go
analogWrite(pwm_motor2,60); // telling motor to activate at 60% PWM
if(encoder_count == Motion_Limit)
analogWrite(pwm_motor,0); // tell motor to stop
}
while(analogRead>1000) // Joystick is pushed to the right
{
digitalWrite(directionMotor,RIGHT); // telling motor what direction to go
analogWrite(pwm_motor2,60); // telling motor to activate at 60% PWM
if(encoder_count == Motion_Limit)
analogWrite(pwm_motor,0); // tell motor to stop
}
} // end case statement
Again, no matter what mode of operation the program is in, it should stop when the count has been reached. Even when the motion limit has been reached, the program should still allow the joystick control to drive the motor away from the motion limit. That is, if count == 20 on the right limit, I can still drive the motor left. Essentially, the encoder should be tracking the motor at all moments in operation.
Questions:
1. How do I declare a interrupt on a MSP432?
2. Can I use a incremental encoder for as a interrupt? Most examples I've found use a button that outputs a high or low signal as a flag for a interrupt. I'm not sure I can do the same thing with a encoder
Your code looks a lot like Arduino code, to attach an interrupt you should use the Arduino attachInterrupt() function. If you are using a different high level support
library then its documentation should include some interrupt examples.
As to the meat of your question.
Your incremental encoder should have two lines, one to indicate left motion, one to indicate right motion.
You will need to alter the global variable encoder_count up and down as indicated by these lines. This should definitely be done using an interrupt for each line. The interrupt should fire on the edge transition as specified in the encoder's datasheet. There is no difference between triggering on a button edge and an encoder edge (except that buttons are messy and need to be debounced, find a non-debounced example).
If it is very important to stop the motor exactly on the incremental count you can test the values in the incremental encoder increment/decrement interrupts and disable the motor if required.
However it is probably sufficient to do the test as part of your main loop. (Side note: remember you need to handle when the joystick is centered.)
I would also recommend creating a function to control the motor. This abstracts away the implementation details, allowing your main loop to focus on higher level functionality. Ensuring the motor control is always done by one function also allows you to guarantee that your limits are always applied.

STM32 - TIM2_ETR pin, connected to pin PA0 (button), incrementing the timer in strange way

I am trying to implement PWM LED dimming in 6 stages, where each stage in more bright, based on clicking button, which increments external pin, which serves the value to timer.
I am facing a problem, that sometimes, value variable is too large than it should be and skips some levels of brightness. For example, value increments: 1,2,3, then jumps to 6,7, etc.
Can anybody pinpoint where is the mistake I am making.
Here is the code:
//EDIT: code removed, because it is a school assignment
This looks like contact bouncing. When input is processed by the CPU, a simple way to solve it is to disable input for a certain duration after an event is detected. Since you directly control timer input from a button, you may not have much control. However, I would experiment with the ETF field of the SMCR register (which in your case is likely set by the sClockSourceConfig.ClockFilter field) and the clock divisor CKD of the CR1 register (which seems like htim2.Init.ClockDivision in your code) (sorry, I am not familiar with STM libraries).

Produce tones at certain time-interval using C programming

Im using C language for a PIC18F to produce tones such that each of them plays at certain time-interval. I used PWM to produce a tone. But I don't know how to create the intervals. Here is my attempt.
#pragma code //
void main (void)
{
int i=0;
// set internal oscillator to 1MHz
//OSCCON = 0b10110110; // IRCFx = 101
//OSCTUNEbits.PLLEN = 0; //PLL disabled
TRISDbits.TRISD7 = 0;
T2CON = 0b00000101; //timer2 on
PR2 = 240;
CCPR1L = 0x78;
CCP1CON= 0b01001100;
LATDbits.LATD7=0;
Delay1KTCYx(1000);
while(1);
}
When I'm doing embedded programming, I find it extremely useful to add comments explaining exactly what I'm intending when I'm set configuration registers. That way I don't have to go back to the data sheets to figure out what 0x01001010 does when I'm trying to grok the code the next time I have to change it. (Just be sure to keep the comments in sync with the changes).
From what I can decode, it looks like you've got the PWM registers set up, but no way to change the frequency at your desired intervals. There are a few ways to do it, here are 2 ideas:
You could read a timer on startup, add the desired interval to get a target time, and poll the timer in the while loop. When the timer hits the target, set a new PWM duty cycle, and add the next interval to your target time. This will work fine, until you need to start doing other things in the background loop.
You could set timer0's count to 0xFFFF-interval, and set it to interrupt on rollover. In the ISR, set the new PWM duty cycle, and reset timer0 count to the next interval.
One common way of controlling timing in embedded processes looks like this:
int flag=0;
void main()
{
setup_interrupt(); //schedule interrupt for desired time.
while (1)
{
if (flag)
{
update_something();
flag = 0;
}
}
Where does flag get set? In the interrupt handler:
void InterruptHandler()
{
flag = 1;
acknowledge_interupt_reg = 0;
}
You've got all the pieces in your example, you just need to put them together in the right places. In your case, update_something() would update the PWM. The logic would look like: "If it's on, turn it off; else turn it on. Update the tone (duty cycle) if desired"
There should be no need for additional delays or pauses in the main while loop. The goal is that it just runs over and over again, waiting for something to do. If the program needs to do something else at a different rate, you can add another flag, which is triggered completely independently, and the timing of the two tasks won't interfere with each other.
EDIT:
I'm now confused about what you are trying to accomplish. Do you want a series of pulses of the same tone (on-off-on-off)? Or do you want a series of different notes without pauses (do-re-me-fa-...)? I had been assuming the latter, but now I'm not sure.
After seeing your updated code, I'm not sure exactly how your system is configured, so I'm just going to ask some questions I hope are helpful.
Is the PWM part working? Do you get the initial tone? I'm assuming yes.
Does your hardware have some sort of clock pulse hooked up to the RA4/T0CKI pin? If not, you need T0 to be clock mode, not counter mode.
Is the interrupt being called? You are setting INT0IE, which enables the external interrupt, not the timer interrupt
What interval do you want between tone updates? Right now, you are getting 0xFFFF / (clock_freq/8) You need to set the TMR0H/L registers if you want something different.
What's on LATD7? and why are you clearing it? Are you saying it enables PWM output?
Why the call to Delay()? The timer itself should be providing the needed delay. There seems to be a disconnect about how to do timing. I'll expand my other answer
Where are you trying to change the PWM frequency? Don't you need to write to PR2? You will need to give it a different value for every different tone.
"Halting build on first failure as requested."
This just says you have some syntax error, without showing us the error report, we can't really help.
In Windows you can use the Beep function in kernel32:
[DllImport("kernel32.dll")]
private static extern bool Beep(int frequency, int duration);

Resources