What I’m working on right now…

I’ve been experimenting with creating fractal images using iterating functions of the form

$z_{n+1} = \frac{z_n^a + c}{z_n^b - c}$
where
$z_0 = 0$.

Without getting into all the details right now, within each frame of the animation every pixel represents a different value of the complex variable c. For a given value of c, the number of iterations required for the magnitude of z_n to pass a pre-defined threshold determines the colour of the corresponding pixel. If the sequence exceeds the limit within a small number of iterations, the pixel will be white. Conversely, if the magnitude of z_n remains within the threshold until the maximum number of iterations is reached, the pixel ends up black.

In the following animation, a remains constant (a=5.0) from frame to frame while b is incremented in steps of 0.01 from 0.0 to 4.0. The region of the complex plane shown is -2 < Re{c} < 0 and 0 < Im{c} < 2.

I used the following Python script to generate the individual frames of the animation:

#
# fractal_movie.py - Written by Ted Burke, last updated 7-1-2016
#

import subprocess
import math

centre = 0 + 2j   # complex value at centre of image
w,h = 800,400     # image width and height
pxw = 0.01        # pixel width
limit = 4.0       # once z reaches this value, iteration ceases

# Create a buffer to store a row of pixel values
row = w*[0]

# Create fractal image files
for t in range(401):

a = 5
b = t/100.0

# Open file
pgmfilename = 'crpf_a{:1.3f}_b{:1.3f}_pxw{:.3f}_lim{:1.1f}_{:d}x{:d}px.pgm'.format(a, b, pxw, limit, w, h)
print(pgmfilename)
pgmfile = file(pgmfilename, 'w')
pgmfile.write('P5\n{} {}\n255\n'.format(w,h))

# Generate image
for y in range(h):
for x in range(w):
c = centre + complex(((x-(w-1)/2.0)*pxw),(((h-1)/2.0-y)*pxw))
z = 0
n = 0
while abs(z) < limit and n < 51:
try:
z = (pow(z,a) + c)/(pow(z,b) - c)
n = n + 1
except ZeroDivisionError:
z = limit
row[x] = int(255 * (0.5 + 0.5*math.cos(math.pi*n/51.0)))
pgmfile.write(bytearray(row))

# Close file
pgmfile.close()

subprocess.call('mogrify -format png ' + pgmfilename, shell=True)
subprocess.call('rm ' + pgmfilename, shell=True)



I used a second Python script to rename the PNG frames as frame001.png, frame002.png, etc.

#
# renamer.py - Written by Ted Burke, last updated 12-1-2016
#

import subprocess

# Create fractal image files
for t in range(401):
b = t/100.0
origfilename = 'crpf_a5.000_b{:1.3f}_pxw0.010_lim4.0_800x400px.png'.format(b)
newfilename = 'frame{:03d}.png'.format(t)
print(origfilename + ' ' + newfilename)
subprocess.call('cp ' + origfilename + ' ' + newfilename, shell=True)



Finally, I used ffmpeg to combine the individual PNG frames into a single video file, as follows:

ffmpeg -framerate 10 -i frame%03d.png -c:v libx264 -pix_fmt yuv420p out.mp4


Simple 2-channel hardware PWM example for the MSP430G2452 microcontroller

//
// 2-channel hardware PWM example for MSP430G2452
// Written by Ted Burke - last updated 2-11-2015
//

#include <msp430.h>

int main( void )
{
// Watchdog timer
WDTCTL = WDTPW + WDTHOLD; // Disable watchdog timer

// Configure P1.2 (TA0.1) and P1.4 (TA0.2) for PWM output
// To configure P1.2 as TA0.1: P1DIR.2=1, P1SEL.2=1, P1SEL2.2=0
// To configure P1.4 as TA0.2: P1DIR.4=1, P1SEL.4=1, P1SEL2.4=1
P1DIR  = 0b00010100;
P1SEL  = 0b00010100;
P1SEL2 = 0b00010000;

// Configure Timer A
TACTL = TASSEL_2 + ID_0 + MC_1; // Up mode, input divider=1, SMCLK clock
TACCTL0 = OUTMOD_7;             // TA0.0 in Reset/Set output mode
TACCTL1 = OUTMOD_7;             // TA0.1 in Reset/Set output mode
TACCTL2 = OUTMOD_7;             // TA0.2 in Reset/Set output mode
TACCR0  = 20000;                // Start timer with 20ms period

while(1)
{
// P1.2 dim and P1.4 bright for 1 second
TACCR1 = 2000;
TACCR2 = 8000;
__delay_cycles(1000000);

// P1.2 bright and P1.4 dim for 1 second
TACCR1 = 8000;
TACCR2 = 2000;
__delay_cycles(1000000);
}

return 0;
}

Posted in Uncategorized | 2 Comments

RoboSlam @ Dublin Maker – only two days away!

Looking forward to Dublin Maker on Saturday in Trinity! Entry is free and all are welcome. Our stand will be the one where humans are getting tricked into building a robot army.

Ted’s robot design for Dublin Maker event on Saturday at Trinity College Dublin. Come build one for free! And, it’s just 12 Euro (less than the cost to us) if you want to take it home with you.

Hello RoboSlammers,

This is just a quick reminder – it is only two days now to Saturday’s big event – Dublin Maker! The weather forecast is looking good so far – “cool and dry with scattered showers” according to met.ie. The event will open at 10am and run until 6pm. It tends to get busy at around midday. A description of some of the main participants at Dublin Maker 2015 is available here. Personally, we can’t wait to see what mechanical wonders Michal Mizsta the “dragon dude”, will have on show this year. And there is an interesting range of exhibits.

Shannon, Damon, Frank, and Ted getting ready today…

View original post 239 more words

Generating antiphase PWM signals with the dsPIC30F4011

I frequently receive queries from people who are using a dsPIC microcontroller to control power electronics of some kind, such as in an inverter, a voltage converter, or similar. Many of these queries relate to the generation of different combinations of pulse-width modulation (PWM) signals. In this article, I describe a simple example application in which the dsPIC30F4011 is used to generate two antiphase PWM signals with duty cycle varying between 10% and 45%. By antiphase, I mean that the two signals are 180 degrees (π radians) out of phase with each other. Apart from that, the two signals are identical.

I developed this example in response to a query from gunz which was posted as a comment on another article that I published on this blog a couple of years ago. In that article, I also generated antiphase PWM signals, but I used two of the dsPIC30F4011’s three PWM channels. Specifically, the signals were generated on pins PWM1H and PWM2L. Gunz asked how to generate the signals on the high and low pins of a single PWM channel (e.g. PWM1H and PWM1L), so that’s what I’m demonstrating in this example.

The signal specification is:

• Two identical PWM signals 180 degrees out of phase.
• The PWM frequency is 15kHz.
• The duty cycle varies between 10% and 45% (hence the pulses on the two outputs never overlap).
• The output pins are PWM1H and PWM1L.

The basic code is as follows:

//
// This dsPIC30F4011 example program generates PWM signals
// on PWM1H and PWM1L. The signals are identical except that
// they are 180 degrees out of phase. Duty cycle can vary
// between 0.1 and 0.45. PWM frequency is constant at 15kHz.
//
// The basic idea is to configure the PWM frequency to double
// what we want (30 kHz), but then only generate a pulse on
// each output every second period. We use the PWM interrupt
// (which is triggered every time the PWM timebase reaches
// the value PTPER and goes back to zero) to switch back and
// forth between PWM1H and PWM1L. i.e. The two pins take it
// in turns to output pulses.
//
// Written by Ted Burke - last updated 11-4-2015
//

#include <xc.h>
#include <libpic30.h>

// Configuration settings
_FOSC(CSW_FSCM_OFF & FRC_PLL16); // Fosc=16x7.5MHz, Fcy=30MHz
_FWDT(WDT_OFF);                  // Watchdog timer off
_FBORPOR(MCLR_DIS);              // Disable reset pin

//
// The PWM interrupt is triggered each time PTMR reaches the same
// value as PTPER and resets to zero. We use this ISR to switch back
// and forth between outputting a pulse on PWM1H and outputting a pulse
// on PWM1L. During each PTMR period, we override one or other pin to
// lock it at 0, suppressing its pulse. Because the OSYNC bit is set,
// PWM override changes do not take effect until the next time PTMR
// resets to zero. Updates therefore don't take effect until the start
// of the the next cycle.
//
void __attribute__((interrupt, auto_psv)) _PWMInterrupt(void)
{
// Reset PWM interrupt flag
_PWMIF = 0;

// Alternate between overriding PWM1L and overriding PWM1H.
// Whichever pin is overridden will be driven low during
// the next PWM period, suppressing its output pulse.
if (_POVD1H)
{
_POVD1H = 0;
_POVD1L = 1;
}
else
{
_POVD1L = 0;
_POVD1H = 1;
}
}

int main(void)
{
// Configure RD0 as a digital output for an indicator LED
TRISD = 0b1110;

// Configure PWM
//
// Note: To provide higher PWM duty cycle resolution, the dsPIC's
// PDCx unit is only half as long as its PTPER unit. For example,
// when PDC1 = PTPER, the PWM1 duty cycle is actually only 50%.
// Furthermore, in this example, since we are alternating back and
// forth between pulses on two outputs, each output only produces
// every second pulse. Hence, in this case PTPER is really only
// half of the full signal period. Yes, it's potentially confusing!
//
_PMOD1 = 1;   // Enable PWM channel 1 in independent mode
_PEN1H = 1;   // Enable PWM1H pin
_PEN1L = 1;   // Enable PWM1L pin
_POUT1L = 0;  // When PWM1L is overriden, set it low
_POUT1H = 0;  // When PWM1H is overriden, set it low
_POVD1L = 1;  // Initially, enable override on PWM1L
_POVD1H = 0;  // Initially, disable override on PWM1H
_OSYNC = 1;   // Synchronise PWM override changes with PTMR reset
_PWMIE = 1;   // Enable PWM interrupt
_PTCKPS = 0;  // prescale=1:64 (0=1:1, 1=1:4, 2=1:16, 3=1:64)
PTPER = 999;  // Set PWM frequency to 30 kHz
PDC1 = 400;   // Set duty cycle to 10%
_PTEN = 1;    // Enable PWM time base

// Now just blink an LED while the PWM ISR does the heavy lifting
while(1)
{
_LATD0 = 1;          // Turn on LED on RD0
__delay32(15000000); // 0.5 second delay
_LATD0 = 0;          // Turn off LED on RD0
__delay32(15000000); // 0.5 second delay
}

return 0;
}


I compiled the above code using Microchip’s free XC16 C compiler. This is my build script, which produces an binary file called “a.hex”:

xc16-gcc main.c -mcpu=30F4011 -Wl,--script=p30F4011.gld
if errorlevel 0 xc16-bin2hex a.out


I downloaded the file “a.hex” onto the dsPIC30F4011 using a PICkit 2 USB programmer. I don’t use MPLAB at all, so I just used the PICkit 2 software application (V 2.61 can be downloaded here).

The breadboard circuit I used for testing is shown below. In addition to the voltage supply connections I included in my circuit, I highly recommend connecting pin 20 (VSS) and pin 21 (VDD) to the voltage supply rails. In the past, I have tended not to bother connecting all voltage supply pins, but I have recently run into some very strange problems that it took me a long time to realise could be completely solved by connecting more voltage supply pins. Specifically, I had a lot of problems with mysterious resetting of the dsPIC when using PWM interrupts in parallel with mainline code (such as the LED flashing code I put in the main function in this example). I therefore highly recommend connecting all of the dsPIC’s voltage supply pins, even if it seems redundant.

An indicator LED (with 220\Omega; current-limiting resistor in series) is connected to RD0 (pin 23). The three wires which extend beyond the lower edge of the image are the oscilloscope connections – green is ground and the two blue wires connect PWM1H and PWM1L to different channels of the scope.

This is how the circuit appeared once the code shown above was running. The LED on RD0 simply blinks on and off once a second.

I displayed the signals from PWM1H and PWM1L on the two channels of an oscilloscope. As shown below, the two signals are identical but 180 degrees out of phase.

The following modified version of the previous example shows how the PWM ISR can be used to update the duty cycle as well as alternating the generated pulses between the two outputs. Apart from comments, the only change from the previous example is the addition of lines 62-68 to the PWM ISR (the _PWMInterrupt function) which modulate the PWM duty cycle.

//
// This dsPIC30F4011 example program generates PWM signals
// on PWM1H and PWM1L. The signals are identical except that
// they are 180 degrees out of phase. This is a slightly
// modified version of the example in which duty cycle is
// modulated in a sawtooth pattern, increasing in small steps
// from 0.1 all the wat to 0.45, then resetting to 0.1 over
// and over again. PWM frequency is constant at 15kHz.
//
// The basic idea is to configure the PWM frequency to double
// what we want (30 kHz), but then only generate a pulse on
// each output every second period. We use the PWM interrupt
// (which is triggered every time the PWM timebase reaches
// the value PTPER and goes back to zero) to switch back and
// forth between PWM1H and PWM1L. i.e. The two pins take it
// in turns to output pulses.
//
// Written by Ted Burke - last updated 11-4-2015
//

#include <xc.h>
#include <libpic30.h>

// Configuration settings
_FOSC(CSW_FSCM_OFF & FRC_PLL16); // Fosc=16x7.5MHz, Fcy=30MHz
_FWDT(WDT_OFF);                  // Watchdog timer off
_FBORPOR(MCLR_DIS);              // Disable reset pin

//
// The PWM interrupt is triggered each time PTMR reaches the same
// value as PTPER and resets to zero. We use this ISR to switch back
// and forth between outputting a pulse on PWM1H and outputting a pulse
// on PWM1L. During each PTMR period, we override one or other pin to
// lock it at 0, suppressing its pulse. Because the OSYNC bit is set,
// PWM override changes do not take effect until the next time PTMR
// resets to zero. Updates therefore don't take effect until the start
// of the the next cycle.
//
void __attribute__((interrupt, auto_psv)) _PWMInterrupt(void)
{
// Reset PWM interrupt flag
_PWMIF = 0;

// Alternate between overriding PWM1L and overriding PWM1H.
// Whichever pin is overridden will be driven low during
// the next PWM period, suppressing its output pulse.
if (_POVD1H)
{
_POVD1H = 0;
_POVD1L = 1;
}
else
{
_POVD1L = 0;
_POVD1H = 1;
}

// This addition to the PWM ISR modulates the duty cycle in
// a sawtooth pattern. Every 100th time the ISR runs, the
// duty cycle is increased by incrementing PDC1. When the
// duty cycle reaches 45%, it is reset to 10%.
static int n=0;
n = (n + 1) % 100;
if (n==0)
{
PDC1 = PDC1 + 1;
if (PDC1 > (0.45 * 4 * PTPER)) PDC1 = 0.1 * 4 * PTPER;
}
}

int main(void)
{
// Configure RD0 as a digital output for an indicator LED
TRISD = 0b1110;

// Configure PWM
//
// Note: To provide higher PWM duty cycle resolution, the dsPIC's
// PDCx unit is only half as long as its PTPER unit. For example,
// when PDC1 = PTPER, the PWM1 duty cycle is actually only 50%.
// Furthermore, in this example, since we are alternating back and
// forth between pulses on two outputs, each output only produces
// every second pulse. Hence, in this case PTPER is really only
// half of the full signal period. Yes, it's potentially confusing!
//
_PMOD1 = 1;   // Enable PWM channel 1 in independent mode
_PEN1H = 1;   // Enable PWM1H pin
_PEN1L = 1;   // Enable PWM1L pin
_POUT1L = 0;  // When PWM1L is overriden, set it low
_POUT1H = 0;  // When PWM1H is overriden, set it low
_POVD1L = 1;  // Initially, enable override on PWM1L
_POVD1H = 0;  // Initially, disable override on PWM1H
_OSYNC = 1;   // Synchronise PWM override changes with PTMR reset
_PWMIE = 1;   // Enable PWM interrupt
_PTCKPS = 0;  // prescale=1:64 (0=1:1, 1=1:4, 2=1:16, 3=1:64)
PTPER = 999;  // Set PWM frequency to 30 kHz
PDC1 = 400;   // Set duty cycle to 10%
_PTEN = 1;    // Enable PWM time base

// Now just blink an LED while the PWM ISR does the heavy lifting
while(1)
{
_LATD0 = 1;          // Turn on LED on RD0
__delay32(15000000); // 0.5 second delay
_LATD0 = 0;          // Turn off LED on RD0
__delay32(15000000); // 0.5 second delay
}

return 0;
}


Here’s a short video showing the sawtooth modulation of the PWM duty cycle displayed on the oscilloscope.

Posted in Uncategorized | | 2 Comments

Very simple Python / Tkinter GUI to send selected keystrokes via serial port

Following a query from Naomi Dickerson, I was playing around with my SerialSend program, which I often use for sending arbitrary bytes or characters to a connected microcontroller circuit. Sometimes, it’s convenient to send keystrokes in real time i.e. each keystroke is sent as soon as the user strikes the key. This could be done in a Windows console using something like getch(), but in this case I’ve chosen to use Python and Tkinter instead, supported by the PySerial module. Python is absolutely great for automating serial port chit chat. I’ve never found anything better for opening, reading, writing and closing a serial port in just a few lines of code.

Here’s what my ultra simple GUI (if you can even call it that) looks like:

Here’s the full Python code, which I saved as the file “keysender.py”:

# import libraries for serial port and Tkinter GUI
import serial
import Tkinter

# Open serial port
ser = serial.Serial('/dev/ttyUSB0', baudrate=9600, timeout=1)

# Create the root window
root = Tkinter.Tk()
root.geometry('400x200+100+100')
root.title('Serial Keystoke Sender')

# Create a keystroke handler
def key(event):
if (event.char == 'q'):
root.quit()
elif event.char >= '0' and event.char <= '9':
print 'keystroke:', repr(event.char)
ser.write(event.char)

# Create a label with instructions
label = Tkinter.Label(root, width=400, height=300, text='Press 0-9 to send a number, or "q" to quit')
label.pack(fill=Tkinter.BOTH, expand=1)
label.bind('<Key>', key)
label.focus_set()

# Hand over to the Tkinter event loop
root.mainloop()

# Close serial port
ser.close()


The above code should be cross-platform compatible apart from the serial port name ‘/dev/ttyUSB0’, which is what my USB-to-serial converter appears as here in Crunchbang Linux. In Windows, I think you can either replace ‘/dev/ttyUSB0’ with your COM port name in inverted commas (e.g. ‘COM23’) , or even just a device number (0, 1, 2 or whatever).

Python itself is installed by default in Crunchbang, but I needed to install PySerial and Tkinter:

sudo apt-get install python-tk
sudo apt-get install python-serial


I ran my code as root so that I would have access to the serial port device:

sudo python keysender.py


There are more elegant ways to handle this by configuring file permissions or whatever, but for this kind of hardware hacking I’m happy enough to just sudo it.

Posted in Uncategorized | 2 Comments

Using a dsPIC30F4011 to generating 4 PWM signals with equal duty cycles but at 90 degree phase increments

In a recent comment on one of my blog posts, Saptarshi De posed an interesting problem: How can the dsPIC30F4011 be used to generate four PWM signals of equal (but variable) duty cycle at 90 degree phase increments? Saptarshi wants to control a 4-phase interleaved boost converter and he supplied an illustration similar to the following to show what he requires:

The required PWM frequency is 50kHz and the four PWM signals must have equal duty cycle, but that duty cycle is variable. Saptarshi didn’t specify maximum and minimum values for the duty cycle, so I worked on the assumption that it can vary all the way from 0-100%.

At first, I was stumped. The most obvious approaches all have seemed to have show-stopping snags:

• The dsPIC30F PWM module does most of what’s needed, but sadly only provides three channels. Each channel has two outputs, so it may somehow be possible to coax two of the channels to produce complementary output with appropriate deadtime to yield the required four PWM signals, but I couldn’t figure out how.
• The Output Compare module provides four channels which can be used to generate PWM signals, but each of those channels must use either Timer 2 or Timer 3 as its timebase, which imposes some major limitations.

Ultimately, I opted for a variation of the second approach above using the Output Compare channels. Unfortunately, my solution requires that two of the channels be inverted externally, for example using a CMOS logic IC. If the duty cycle range is more constrained, this can be avoided, but for arbitrary duty cycle anywhere between 0% and 100%, I couldn’t work out how to do it without externally inverting two of the signals.

My solution is very similar to what I did previously to generate two out of phase PWM signals having identical duty cycle.

My approach is as follows:

• The dsPIC uses the internal fast RC oscillator with 16x PLL multiplier so that it runs at 30 MIPS. Fcy = 30e6 and Tcy = 33.33ns.
• Timer 2 and Timer 3 are configured with the same period of 600 * Tcy = 20us.
• TMR2 is initialised to 150 and TMR3 is initialised to 0. The result is that when the timers are enabled, TMR2 leads TMR3 by a quarter cycle.
• PWM1 is obtained from OC1 which uses Timer 2 as its timebase.
• PWM2 is obtained from OC2 which uses Timer 3 as its timebase (lagging OC1 by 25% of a cycle).
• PWM3 is obtained by inverting OC3 which uses Timer 2 as its timebase. The pulses on OC3 become the gaps between the pulses in PWM3.
• PWM4 is obtained by inverting OC4 which uses Timer 3 as its timebase. The pulses on OC4 become the gaps between the pulses in PWM4.
//
// This dsPIC30F4011 example program generates four
// interleaved PWM signals to control a 4-phase
// interleaved boost circuit.
//
// Written by Ted Burke - last updated 5-3-2015
//

#include <xc.h>
#include <libpic30.h>

// Configuration settings
_FOSC(CSW_FSCM_OFF & FRC_PLL16); // Fosc=16x7.5MHz, Fcy=30MHz
_FWDT(WDT_OFF);                  // Watchdog timer off
_FBORPOR(MCLR_DIS);              // Disable reset pin

int main()
{
// Configure RD0, RD1, RD2, RD3 as digital outputs.
// (Not sure if this is required when Output Compare is used)
TRISD = 0b1111111111110000;

// Set period and duty cycle
float dutycycle = 0.2;      // 20% duty cycle for this example
int pulse, space, period;   // pulse width, space width, period
period = 600;               // f_m = 30e6 / 600 = 50 kHz
pulse = dutycycle * period; // width of PWM pulses
space = period - pulse;     // gap between PWM pulses

// Configure Timers 2 & 3
PR2 = period - 1;      // Set Timer 2 period for 50kHz
PR3 = period - 1;      // Set Timer 3 period for 50kHz
T2CONbits.TCKPS = 0;   // 1:1 prescale
T3CONbits.TCKPS = 0;   // 1:1 prescale
TMR2 = period / 4;     // Timer 2 leads Timer 3 by 25% of period.
TMR3 = 1;              // Timer 3 lags Timer 2 by 25% of period. Give it a "head start" of 1 because Timer3 is enabled just after Timer2

// Select timer for each channel
OC1CONbits.OCTSEL = 0; // OC1 driven by Timer 2
OC2CONbits.OCTSEL = 1; // OC2 driven by Timer 3
OC3CONbits.OCTSEL = 0; // OC3 driven by Timer 2
OC4CONbits.OCTSEL = 1; // OC4 driven by Timer 3

// Output continuous pulses on all OC channels
OC1CONbits.OCM = 0b101;
OC2CONbits.OCM = 0b101;
OC3CONbits.OCM = 0b101;
OC4CONbits.OCM = 0b101;

// Set OC1 to output continuous pulses of the desired width.
// The pulses are positioned midway through the TMR2 up-count.
OC1R = space / 2;       // pulse start time
OC1RS = OC1R + pulse;   // pulse end time

// Set OC2 to output continuous pulses of the desired width.
// The pulses are positioned midway through the TMR3 up-count.
OC2R = space / 2;       // pulse start time
OC2RS = OC2R + pulse;   // pulse end time

// Set OC3 to output continuous pulses. These will be inverted
// to become the gaps between the pulses and vice versa. The
// width of these pulses is therefore set to the width of the
// gap between the final pulses in PWM3.
OC3R = pulse / 2;       // pulse start time (start of gap in PWM3)
OC3RS = OC3R + space;   // pulse end time (end of gap in PWM3)

// Set OC4 to output continuous pulses. These will be inverted
// to become the gaps between the pulses and vice versa. The
// width of these pulses is therefore set to the width of the
// gap between the final pulses in PWM4.
OC4R = pulse / 2;       // pulse start time (start of gap in PWM4)
OC4RS = OC4R + space;   // pulse end time (end of gap in PWM4)

// Enable Timers 2 & 3
//
// It might be better to use some inline assembly language here
// to ensure that the delay between the two timers being enabled
// is very short and that we know exactly how many instruction
// cycles "head start" Timer 3 should get to make the two timers
// exactly 90 degrees out of phase.
//
T2CONbits.TON = 1; // Enable Timer 2
T3CONbits.TON = 1; // Enable Timer 3

// Now just let the Output Compare module to the work
while(1);

return 0;
}


I saved the program as “main.c” and compiled it using Microchip’s free XC16 C compiler, with the following simple build script:

xc16-gcc main.c -mcpu=30F4011 -Wl,--script=p30F4011.gld
if errorlevel 0 xc16-bin2hex a.out


My test circuit is shown below:

[ Download editable Inkscape SVG version (same SVG file as earlier illustration) ]

I didn’t have an inverter IC available when I was doing this test, so I just cobbled together a couple of crappy NPN transistor inverters (I used BC237 transistors). These don’t respond fast enough for the system to work at 50 kHz, so I temporarily reduced the dsPIC clock speed by a factor of 4 for this experiment.

I tested the circuit using a two channel digital oscilloscope, so I wasn’t able to view all four signals simultaneously. Instead, I displayed PWM1 on scope channel 2 (the blue signal in each of the photos below) and then used scope channel 1 to view PWM2, PWM3 and PWM4 one at a time so that I could verify the phase shift of each signal relative to PWM1.

The photo below shows the signals PWM1 (blue) and PWM2 (yellow).

The photo below shows the signals PWM1 (blue) and PWM3 (yellow). Note that PWM3 is obtained by inverting the signal from OC3.

The photo below shows the signals PWM1 (blue) and PWM4 (yellow). Note that PWM4 is obtained by inverting the signal from OC4.

Posted in Uncategorized | | 18 Comments

Faster Mandelbrot image generation using numpy in Python

#
# fractal.py - Mandelbrot image generation using numpy
# Written by Ted Burke - last updated 2-11-2014
#

import numpy

# Define image size and region of the complex plane
w,h = 1280,1280
remin,remax = -2.0, 2.0
immin,immax = -2.0, 2.0

# Create numpy arrays for pixels and complex values
p = numpy.zeros((h, w), dtype=numpy.uint8)
z = numpy.zeros((h, w), dtype=complex)
c = numpy.linspace(remin,remax,w) * numpy.ones((h,w)) + \
1j * numpy.linspace(immax,immin,h).reshape(h,1) * numpy.ones((h,w))

# Iterative pixel calculation
for n in range(255):
z = z*z + c
p = p + (abs(z) < 2.0)

# Output image to binary PGM file
f = open('fractal.pgm', 'wb')
f.write('P5\n{0} {1}\n255\n'.format(w, h))
f.write(p)
f.close()


I ran the program and converted the image to PNG format using ImageMagick as follows:

python fractal.py
convert fractal.pgm fractal.png