Generate square wave for analog input/output on software - c

I have a device, and it has digital i/o, analog i/o. I send to device below commands for communication.The device has gpio module. My device documantation is here
Write to digital input : gpio set/clear x
Read from digital output : gpio read x
Read from digital output : adc read x
(x : pin number)
How can I create sine/square wave and calculate amplitude? To create square wave :
open device
sleep
write to device low mode(t0)
sleep
write to device high mode
sleep
write to device low mode(t1)
period = (t1 - t0)
Is this a square wave?

it seems your example is indeed square wave
if write to device low mode(t0) sets the output pin to low and write to device low mode(t1) to high or reverse then period is the sum of the sleeps + some time for setting up GPIO state. Don't know why you have times inside the GPIO set lines and not in sleeps ... (may be something platform dependent?)
To go to sin wave
use DAC or PWM + RC filter with some precomputed amplitude table in which the index is increasing periodically.
BYTE sintab[32]={ 128,...,255,...,128,...,0,....,127 };
encoded: 128 is zero, 255 is +1 and 0 is -1; now just add some index:
int ix=0'
and once in a while (on some timer perhaps) increment it and set the output to new value:
ix=(ix+1)&31;
that and 31 just cause tho cycle the index from start again if end reached (sintab must be of size power of 2). The period is timer frequency/sintab size
[notes]
You can modify this to your purpose for example make sintab[][] a 2D array where first index means amplitude and second is the ix as now. On older platforms (MCU's) you can encode the PWM sequence directly to sintab end so on ...
You can pre-compute the sintab values like this:
sintab[ix]=128.0+127.0*sin(float(2.0*M_PI*ix)/32.0);
or if your platform supports fast enough sin you can use above line directly without the actual array ...
[edit1]
for sinwave you can use just 0/1 states. If you need analog output and:
You have DAC (digital to analog converter)
then send the actual amplitude to it like dac write sintab[ix]; that will create the analog voltage on the output pin for you.
You do not have any spare DAC's use PWM Pulse Width Modulation instead
it is an old school trick to avoid the need of DAC and still have analog output from digital pin. It works like this:
The output value is the cumulative energy/voltage per time chunk so you generate square-wave signal
ratio 1:1 means that half the period is H and the rest L
ratio 2:1 means that 2/3 of the period is H and the rest L
The more time the output is H the bigger output value. This is still digital output but if you connect on it any nonlinear device like capacitor or coil then the energy inertia will cause to drop the H voltage to some level dependent on the square-wave ratio. Most common is the RC filter (R is serial and C is parallel to ground). If you want to drive some coil (motor) then you do not need the filter. This kind of use usually generate high pitch sound (the PWM frequency) often heard near machinery ...
The PWM frequency has to be high enough (many times higher then the sinwave frequency)
Some code for PWM with amplitude and frequency setting:
const int timer_T=1; // used timer interval [ms]
const int PWM_max=10; // PWM max amplitude+1
int PWM_s=0; // PWM actual step
int PWM_t=0; // PWM actual time
int PWM_a=3; // PWM amplitude <0,PWM_ratio_max)
int PWM_T=200; // PWM period [ms]
void OnTimer()
{
int PWM_T0=PWM_T/PWM_max; // PWM step period must be >=1 !!!
PWM_t+=timer_T;
if (PWM_t>=PWM_T0)
{
if (PWM_s<=pwm_a) gpio set x; else gpio clear x;
PWM_s++; if (PWM_s>=PWM_max) PWM_s=0;
PWM_t-=PWM_T0;
}
}

Related

Can anyone help me in below scenario on DAC

I am writing a c program to send a digital voltage value in bits to DAC (SAM4E) in order to get an analog output.
The program is below:
#include "asf.h"
#include "conf_board.h"
#include "conf_clock.h"
#include "dacc_example.h"
int main (void)
{
sysclk_init();
board_init();
/* Reset DACC registers */
dacc_reset(DACC_BASE);
/* Half word transfer mode */
dacc_set_transfer_mode(DACC_BASE, 0);
dacc_set_timing(DACC_BASE,0, 0x10);
/* Disable TAG and select output channel DACC_CHANNEL */
dacc_set_channel_selection(DACC_BASE, DACC_CHANNEL);
/* Enable output channel DACC_CHANNEL */
dacc_enable_channel(DACC_BASE, DACC_CHANNEL);
/* Set up analog current */
dacc_set_analog_control(DACC_BASE, DACC_ANALOG_CONTROL);
uint32_t dac_val = 0;
while (1)
{
// set voltage to minimum
#define SET_DAC_VAL 0x000
//set voltage to midpoint
// set voltage to 2.7V
//set voltage to 3.2V
//write the conversion value
dacc_write_conversion_data(DACC_BASE, SET_DAC_VAL, DACC_CHANNEL);
}
}
In the above code, I have configured the DAC and in the while loop I am trying to send the digital values to be converted into data conversion register. I want to set the voltages to minimum, midpoint, 2.7V and 3.2V. The maximum voltage is 3.3v and DAC is of 12 bit resolution.
Can anyone help me to set the voltage ??
or
May I know how we represent 2.7 V in 12 bit binary format??
Can anyone help me to set the voltage ??
Setting the voltage is going to depend on how you are interacting with the DAC. Assuming that you are using a microcontroller, then you need to refer to the datasheet. It will describe the registers in the DAC module and how they work. Most of the time there is a code example in there as well.
May I know how we represent 2.7 V in 12 bit binary format??
Your DAC has a 12-bit resolution. This means that you have 12-bits to represent the voltage value that you want to output on the DAC. This means you can represent 2^12 - 1 increments. Assuming that the DAC has a reference voltage of 3.3V, then each increment is 3.3/(2^12 - 1) volts. So if we wanted 2.7V, it would be represented by the value 2.7/(3.3/(2^12 - 1)) = 3350.

STM32 maximum interrupt handling frequency

I am trying to implement my own SPI communication from FPGA to STM in which my FPGA serve as MASTER and generate Chip enable and clock for communication. FPGA transmit data at its rising edge and receive data at its falling edge my FPGA code works properly.
In STM side i capture this master clock on interrupts and receive data at its rising edge and transmit at its falling edge but communication not work properly if i increase clock speed from 250khz
According to my understand STM work at 168 Mega hz i set clock setting according to 168Mhz and handling of 1mhz interrupt is not a big problem so can you any guide how i handle this high speed clock in STM
My code is written below
/*
* Project name:
EXTI_interrupt (EXTI interrupt test)
* Copyright:
(c) Mikroelektronika, 2011.
* Revision History:
20111226:
- Initial release;
* Description:
This code demonstrates how to use External Interrupt on PD10.
PD10 is external interrupt pin for click1 socket.
receive data from mosi line in each rising edge.
* Test configuration:
MCU: STM32F407VG
http://www.st.com/st-web-
ui/static/active/en/resource/technical/document/datasheet/DM00037051.pdf
dev.board: EasyMX PRO for STM32
http://www.mikroe.com/easymx-pro/stm32/
Oscillator: HSI-PLL, 140.000MHz
Ext. Modules: -
SW: mikroC PRO for ARM
http://www.mikroe.com/mikroc/arm/
* NOTES:
receive 32 bit data from mosi line in each rising edge
*/
//D10 clk
//D2 ss
//C0 MOSI
//C1 FLAG
int read=0;
int flag_int=0;
int val=0;
int rec_data[32];
int index_rec=0;
int display_index=0;
int flag_dint=0;
void ExtInt() iv IVT_INT_EXTI15_10 ics ICS_AUTO {
EXTI_PR.B10 = 1; // clear flag
flag_int=1; //Flag on interrupt
}
TFT_Init_ILI9340();
void main() {
GPIO_Digital_Input(&GPIOD_BASE, _GPIO_PINMASK_10);
GPIO_Digital_Output(&GPIOD_BASE, _GPIO_PINMASK_13); // Set PORTD as
digital output
GPIO_Digital_Output(&GPIOD_BASE, _GPIO_PINMASK_12); // Set PORTD as
digital output
GPIO_Digital_Output(&GPIOD_BASE, _GPIO_PINMASK_14); // Set PORTD as
digital output
GPIO_Digital_Output(&GPIOD_BASE, _GPIO_PINMASK_15); // Set PORTD as
digital output
GPIO_Digital_Input(&GPIOA_IDR, _GPIO_PINMASK_0); // Set PA0 as
digital input
GPIO_Digital_Input(&GPIOC_IDR, _GPIO_PINMASK_0); // Set PA0 as
digital input
GPIO_Digital_Input(&GPIOC_IDR, _GPIO_PINMASK_2); // Set PA0 as
digital input
GPIO_Digital_Output(&GPIOC_IDR, _GPIO_PINMASK_1); // Set PA0 as
digital input
//interupt register
SYSCFGEN_bit = 1; // Enable clock for alternate pin
functions
SYSCFG_EXTICR3 = 0x00000300; // Map external interrupt on PD10
EXTI_RTSR = 0x00000000; // Set interrupt on Rising edge
(none)
EXTI_FTSR = 0x00000400; // Set Interrupt on Falling edge
(PD10)
EXTI_IMR |= 0x00000400; // Set mask
//NVIC_IntEnable(IVT_INT_EXTI15_10); // Enable External interrupt
while(1)
{
//interrupt is not enable until i push the button
if((GPIOD_ODR.B2==0)&&(flag_dint==0))
{ if (Button(&GPIOA_IDR, 0, 1, 1))
{
Delay_ms(100);
GPIOC_ODR.B1=1; //Status for FPGA
NVIC_IntEnable(IVT_INT_EXTI15_10); // Enable External interrupt
}
}
if(flag_int==1)
{
//functionality on rising edge
flag_int=0;
if(index_rec<31)
{
//display data on led
GPIOD_ODR.B13= GPIOC_IDR.B0;
//save data in an array
rec_data[index_rec]= GPIOC_IDR.B0;
//read data
index_rec=index_rec+1;
}
else
{
flag_dint=1;
NVIC_IntDisable(IVT_INT_EXTI15_10);
}
} // Infinite loop
}
}
Without getting into your code specific, see PeterJ_01's comment, the clock rate problem can be explained by a misunderstanding of throughput in your assumtions.
You assume that given that your STM device has a clock of 168Mhz it can sustain the same throughput of interrupts, which you seem to have conservatively relaxed to 1Mhz.
However the throughput of interrupts it will be able to support is given by the inverse of the time it takes the device to process each interrupt. This time includes both the time the processor takes to enter the service routing (ie detect the interrupt, interrupt the current code and resolve from the vector table where to jump to) plus the time taken to execute the service routine.
Lets be super optimistic and say that entering the routine takes 1 cycle and the routing itself takes 3 (2 for the flags you set and 1 for the jump out of the routine). This gives 4 cycles at 168Mhz is 23.81ns, taking the inverse 42Mhz. This can also be computed by dividing the maximum frequency you would achieve (168Mhz) by the number of cycles spent processing.
Hence our really optimistic bound is 42Mhz, but realistically will be lower. For a more accurate estimate you should test your implementation timings and dig into your device's documentation to see interrupt response times.

How to get millisecond resolution from DS3231 RTC

How to get accurate milliseconds?
I need to calculate the delay of sending data from Arduino A to Arduino B. I tried to use DS3231 but I cannot get milliseconds. What should I do to get accurate milliseconds from DS3231?
The comment above is correct, but using millis() when you have a dedicated realtime clock makes no sense. I'll provide you with better instructions.
First thing in any hardware interfacing project is a close reading of the datasheet. The DS3231 datasheeet reveals that there are five possible frequencies of sub-second outputs (see page 13):
32 KHz
1 KHz
1.024 KHz
4.096 KHz
8.192 KHz
These last four options are achieved by various combinations of the RS1 and RS2 control bits.
So, for example, to get exact milliseconds, you'd target option 2, 1KHz. You set RS1 = 0 and RS2 = 0 (see page 13 of the datasheet you provided) and INTCN = 0 (page 9). Then you'd need an ISR to capture interrupts from the !INT/SQW pin of the device to a digital input pin on your Arduino.
volatile uint16_t milliseconds; // volatile important here since we're changing this variable inside an interrupt service routine:
ISR(INT0_vect) // or whatever pin/interrupt you choose
{
++milliseconds;
if(milliseconds == 999) // roll over to zero
milliseconds = 0;
}
OR:
const int RTCpin = 3; // use any digital pin you need.
void setup()
{
pinmode(RTCpin, INPUT);
// Global Enable INT0 interrupt
GICR |= ( 1 < < INT0);
// Signal change triggers interrupt
MCUCR |= ( 1 << ISC00);
MCUCR |= ( 0 << ISC01);
}
If these commands in setup() don't work on your Arduino, google 'Arduino external interrupt INT0'. I've shown you two ways, one with Arduino code and one in C.
Once you have this ISR working and pin3 of the DS3231 connected to a digital input pin of your choosing, that pin will be activated at 1KHz, or every millisecond. Perfect!
// down in main program now you have access to milliseconds, you might want to start off by setting:
// When 1-second RTC changes seconds:
milliseconds = 0; // So you can measure milliseconds since last second.
That's all there is to it. All you need to learn now is how to set the command register using I2C commands and you're all set.
The C code example gains 1ms every second. Should be:
{
if (milliseconds == 999) // roll over to zero
milliseconds = 0;
else
++milliseconds;
}

Controlling a servo with raspberry pi using the hardware PWM with wiringPi

I tried controlling the servo with softPwm using the wiringPi Library but this made the servo stutter.
Therefore I want to use the hardware PWM pin on the Raspberry Pi (GPIO18) with the wiringPi library.
But I don't understand how to set the frequency to 50 Hz and change the duty cycle to have a pulse width ranging from 0.8 ms to 2.5 ms.
I found the following relationship on the internet (i dont know if it is correct):
pwmFrequency in Hz = 19.2e6 Hz / pwmClock / pwmRange.
i know the clock divisor max value is something around 4000 and the Raspberry Pi PWM clock has a base frequency of 19.2 MHz. so this gives me ~4,8KHz.
i already got these settings which should give me ~50Hz using the following relationship:
//put PWM in mark-space mode, which will give you
//the traditional (and easily predictable) PWM
pwmSetMode(PWM_MODE_MS);
//setting ping GPIO 18 as a pwm output
pinMode(18,PWM_OUTPUT);
//Set clock divisor to 4000
pwmSetClock(4000);
pwmSetRange (10) ;
I dont got a oscilloscope to test the output signal to check what setting changes what. this makes it hard to find it out myself.
Long story short:
Can anyone tell me how I can achieve a duty cycle with a pulse width of 0,8ms to 2,1ms for controlling a servo using the hardware PWM on the Raspberry Pi.
I'm a complete newby to Pi and to Servo's. But I got it to work with wiringPi.
It says here that we're looking to create pulse of 1ms to 2ms in length, every 20ms or so. Assuming this 19.2Mhz base clock is indeed correct, setting pwm clock to 400 and pwm range to 1000, should give a pulse at 48Hz or every 20.8 ms. Then setting pwm value to 48 should give you a 1ms long pulse and a pwm value of 96 should give you a 2ms long pulse.
But you need to set the chip in pwm-ms mode.
(Lots of shoulds here, since I do not have an osciolloscope either)
So to set it up:
gpio mode 1 pwm
gpio pwm-ms
gpio pwmc 400
gpio pwmr 1000
And then you can turn the servo from left to right via
gpio pwm 1 48
gpio pwm 1 96
(Actually, the servo I got worked from 28 up to 118; could be the servo)
(The setup sequence seems important; could be a bug)
if (wiringPiSetup () == -1) //using wPi pin numbering
exit (1) ;
pinMode(1, PWM_OUTPUT);
pwmSetMode(PWM_MODE_MS);
pwmSetClock(384); //clock at 50kHz (20us tick)
pwmSetRange(1000); //range at 1000 ticks (20ms)
pwmWrite(1, 75); //theretically 50 (1ms) to 100 (2ms) on my servo 30-130 works ok
return 0 ;
Make sure you are using correct gpio pins!
Models A and B have one hardware PWM on pin 18 BCM (1 wPi).
Models A+ and B+ can output second hardware pwm on pins 13 and 19 BCM (23, 24 wPi)
How about using RPIO instead? Here's the link to the library: http://pythonhosted.org/RPIO/index.html
Here's the PWM example: http://pythonhosted.org/RPIO/pwm_py.html
And you may also use the C source directly: https://github.com/metachris/RPIO/tree/master/source/c_pwm
I got wiringPi to do it through software bit-banging. I might have tried RPIO but my particular application requires that the audio output works, and I understand that RPIO's DMA makes audio go away. I might have also tried wiringPi's softPwm or even softServo, but I also require to run a DC motor through PWM, and I don't want to bring the whole system down to 50Hz just for the servo.
This program worked as a demonstration, has no jitter (because it doesn't continuously drive the positioning pulses), and lands on its target each time with a visibly indistinguishable error. Granted the Pi isn't doing much else at the time to interfere with the program's timing (except running an X server through SSH, gedit, terminal session, everything in top, etc.).
// Servo trial 11/15/14 by SLC
#include <wiringPi.h>
#include <stdio.h>
#include <unistd.h>
int main()
{
wiringPiSetup();
pinMode( 6, OUTPUT );
digitalWrite( 6, HIGH );
int idx = 0, tries = 0;
while ( tries++ < 30 )
{
int i;
const int period[] = { 500, 1500, 2500 };
printf( "Setting period to %i ms\n", period[idx] );
for ( i = 0; i < 20; ++i )
{
// Output going through an inverter (to convert 3.3V to 5V)
digitalWrite( 6, LOW );
usleep( period[idx] );
digitalWrite( 6, HIGH );
usleep( 20 * 1000 );
}
++idx;
idx %= 3;
sleep( 2 );
}
}
My servo is a Radio Shack Micro Servo, which appears identical to the other "micro" servos out there. I also found I could ditch the inverter and just drive the signal using the 3.3V GPIO.

How to control a motor with atmega 32 pwm

I have been for some time on how to control a motor (control its speed) with fast pwm mode with my atmega32. I need to use the 8-bit Timer0, because i have other uses for the other counters. I think I know how to inialise the timer for this task:
void initial_io (void){
DDRC = 0xFF;
DDRB = 0xFF;
PORTA = (1<<PA4)|(1<<PA5);
TCCR0 = (1<<WGM01)|(1<<WGM00); // PWM mode : Fast PWM.
TCCR0 = (1<<CS02)|(1<<CS00); // PWM clock = CPU_Clock/1024
}
But then comes the problem. I simply don't know what to do next, what to do on my main.
My exact project is to drive a remote controlled car with acceleration. So when I ask from the car to go forward it must accelerate from stop to maximum speed whith fixed acceleration. I don't know any Assembly, so if you can help me please do it in C. Any help will be much appreciated.
Well, I guess you're okay with all port B and C pins being outputs. Also, you shouldn't need to do anything in assembly on AVR. The assembly-only stuff is available as macros in avr-libc.
Setup
First off, you're setting up TCCR0 wrong. You have to set all the bits at once, or you have to use a read-modify-write operation (usually TCCR0 |= _BV(bit_num); to set a bit or TCCR0 &= ~_BV(bit_num); to clear it). (_BV(N) is an avr-libc macro that's more legible than the (1<<N) stuff you're using, but does the same thing.) Also, you're missing the polarity of your PWM output, set by the COM00 and COM01 bits. Right now you have them (implicitly) disabled PWM output (OC0 disconnected).
So I'm going to assume you want a positive-going PWM, i.e. larger PWM input values result in larger high-output duty cycles. This means COM01 needs to be set and COM00 needs to be cleared. (See pp. 80-81 of the ATmega32(L) data sheet.) This results in the setup line:
TCCR0 = _BV(WGM01) | _BV(WGM00) // PWM mode: Fast PWM.
| _BV(COM01) // PWM polarity: active high
| _BV(CS02) | _BV(CS00); // PWM clock: CPU_Clock / 1024
Duty Cycle
Now we get to the actual duty cycle generation. Timer 0 is pretty stupid, and hard wires its BOTTOM to 0 and TOP to 0xFF. This means that each PWM period is PWM_Clock / 256, and since you set PWM_Clock to CPU_Clock / 1024, the period is CPU_Clock / 262144, which is about 33 ms for an 8 MHz CPU clock. So each PWM clock, this counter counts up from 0 to 255, then loops back to 0 and repeats.
The actual PWM is generated by the OC circuit per Table 40. For the COM0* setting we have, it says:
Clear OC0 on compare match, set OC0 at BOTTOM
What this means is that each time the counter counts up, it compares the count value to the OCR0 register, and if they match it drives the OC0 output pin to GND. When the counter wraps around to 0, it drives the pin to VCC.
So to set the duty cycle, you just write a value corresponding to that duty cycle into OCR0:
OCR0 = 0; // 0% duty cycle: always GND.
OCR0 = 64; // 25% duty cycle
OCR0 = 128; // 50% duty cycle
OCR0 = 172; // 67% duty cycle
OCR0 = 255; // 100% duty cycle; always VCC. See below.
That last case is there to resolve a common problem with PWM: the number of possible duty cycle settings is always one more than the number of count steps. In this case, there are 256 steps, and if the output could be VCC for 0, 1, 2, … 256 of those steps, that gives 257 options. So rather than prevent either the 0% or 100% case, they make the one-shy-of-100% case disappear. Note 1 on Table 40 says:
A special case occurs when OCR0 equals TOP and COM01 is set. In this case, the compare match is ignored, but the set or clear is done at BOTTOM.
One more thing: if you write to OCR0 in the middle of a PWM cycle, it just waits until the next cycle.
Simulating Acceleration
Now to get the "constant acceleration" you want, you need to have some kind of standard time base. The TOV0 (timer 0 overflow) interrupt might work, or you could use another of the timers or some kind of external reference. You'll use this standard time base to know when to update OCR0.
Constant acceleration just means that the speed changes linearly with time. Taking this a step further, it means that for each update event, you need to change the speed by a constant amount. This is probably nothing more than saturation arithmetic:
#define kAccelStep 4
void accelerate_step() {
uint8_t x = OCR0;
if(x < (255 - kAccelStep))
OCR0 = x + kAccelStep;
else
OCR0 = 255;
}
Just do something like this for each time step and you'll get constant acceleration. A similar algorithm can be used for deceleration, and you could even use fancier algorithms to simulate nonlinear functions or to compensate for the fact that the motor does not instantly go to the PWM-specified speed.
As you seem to be a beginner on AVR programming, I suggest you go the easy way: start with Arduino.
The Arduino environment offers simple functions so you don't need to manipulate the processor registers directly. For instance, to control a PWM output, you simply have to call analogWrite() (documentation here)
Here is a tutorial to hook up a motor to an Arduino.
Here is a tutorial to program a ATMega32 from Arduino IDE

Resources