Welcome to Laser Pointer Forums - discuss green laser pointers, blue laser pointers, and all types of lasers

Buy Site Supporter Role (remove some ads) | LPF Donations

Links below open in new window

FrozenGate by Avery

ARDUINO & DAC for XY projector






One thing you should check is turning off your serial code. That way it's not processing

If I only could figure out how to use the I2C.write command...

First see if the plain byte-writing with that library is fast enough. The I2C library is already faster than Wire, so it might be enough. Still, you can pack the data into three bytes and send that out. I think this is right:

Code:
// Send out the value in 2-byte integer x:
char I2COut[3];
I2COut[0] = 64; // The update command.  This only needs to be set once in the program if you reuse this array

unsigned short x = 1245; // Your unsigned X value

#define WRITE_I2C(ADDR, X) \
    I2COut[1] = (char) (0xFF & ((X) >> 4)); \
    I2COut[2] = (char) (0xFF & ((X) << 4)); \
    I2C.write((ADDR), 0, (void *) I2COut, 2);

WRITE_I2C(DACX, x);

(I also noticed that the code I posted before assumed that the device was in FAST mode, not regular DAC write mode, so I've modified it to the regular write mode like you had before.)

That should be faster than the wire library even if only because the I2C library is a faster library.

You can also speed up the color code (black(), green()) by changing the digitalWrite() commands to direct port manipulations e.g.

Code:
#define SET_D(BIT)   (PORTD |= (1 << BIT))
#define CLEAR_D(BIT)   (PORTD &= ~(1 << BIT))


// Set green:

SET_D(GREEN_PORT_PIN)

You'll have to look up what port pins your digital pins map to (e.g. Arduino - PinMapping168). The above is more applicable to bit-banging rather than something more high level like this where you're only setting/clearing a bit every point. Still, every bit helps.
 
BB is right, and I think you'll find using any of the functions related to the Arduino bootloader is going to make this run too slow to be viable. You'll find most DAC's do only use single core MCU's, but the code is written from scratch, utilizing no libraries, bootloaders or anything like that, allowing it to run much faster.

The Arduino bootloader is a pretty serious speed limitation if you use it.
 
So what do you think?

MISSION IMPOSSIBLE?


Anyway the power supply of the RGB-lasers is acting funny so I stopped testing yesterday.

Additionally I have a businesstrip to Switzerland of 2 days coming up.

Yodela hiti!! Hiti Hiti
 
I've had poor luck using I2C and Arduinos. It's really a protocol made for slow and simple on-board devices, more appropriate for working with EEPROMs than something like a fast DAC. You might be able to get more out of using the FAST mode and that DAC, but if you're going to do that you should look into something like the Teensy 3.0 or Arduino Due so that you at least have the processor to do it. Right now, even just the trig calculations take significant cycles-per-point, and you can't store many points to reduce the calculations because of the small amount of RAM on the regular Arduino.

Still, at least you got the Ardunio to produce a picture without using its onboard PWM "DACs" that are pretty crappy. You can use that knowledge and apply it to other, more advanced MCUs (e.g. Arduino Due, Teensy 3.0)
 
So what do you think?

MISSION IMPOSSIBLE?


Anyway the power supply of the RGB-lasers is acting funny so I stopped testing yesterday.

Additionally I have a businesstrip to Switzerland of 2 days coming up.

Yodela hiti!! Hiti Hiti

You can write fairly high bit rates using the UART module on the 328p. You'll probably want to make a UARTsetup() and a mySerialWrite() function in C to implement this - luckily the IDE supports C.

You can implement a fast changing PWM signal on the board, into the 2 Mhz range if you like. You can use an RC circuit to smooth it out into a varying DC voltage which is the time domain average of the PWM voltage level.

Just some ideas....

I'm not well versed on projector technology.
 
Well, he's using the I2C bus, not the UART. He'd need a RS-232-capable DACs, some way to connect the signal to multiple end-points, and have some processing time left over to do other things. The last part is the main hard limitation of this MCU platform: the ATmega 128/328 is really more for small tasks. It's like trying to force a Volkswagen Bug to perform like a race car. Sure, you can put a Porsche engine into the Bug as a novelty and experiment, but in the end you're still dealing with a Bug and all the limitations of the platform.

As he doesn't need the low-power characteristics, and the cost won't be much more, the best route would probably be to get a decent MCU platform and then some SPI-based DACs. He'll have all the processing speed, memory, etc. as well as extra pins and such to deal with the SPI. SPI has a major advantage over I2C in that it was actually designed to transfer data quickly, not just connect to slow devices in a simple manner. Hell, maybe he can try using SPI DACs on his current Arduino, which would probably be faster, though it'd use up more pins.
 
I have decided to buy an Arduino DUE. That has 2 DAC-s onboard.
Perhaps it is faster.

I saw this tutorial on YouTube:



The code seems to be incredibly simple.

Skip to 3:45 if you want to miss the setup of the Arduino Due itself. ;)


I will let you know the results as soon as I get the board.
 
Last edited:
Just use the part after the "v=" and the youtube tag to link a video. Remember to use preview to see if it works.
 
I'm thinking there's an ASIC out there for this. I don't have much time to do the searching right now - but I may later on tonight.
 
Bionic Badgers comment re: SPI got me thinking and I looked at some SPI DAC and these can be clocked at +30Mhz ! :beer:

So I got hold of a AD5623R-5 dac. This little chip has 2, 12bit channels and has a LDAC line so that you can load each channel registers independantly (coz thats the only way you can do this;)) and then clock the two out together so the X and Y pair appears simultainously using the LDAC control pin.

The other + point about the SPI is that the Arduino library uses the ATMega on board SPI hardware - cool.

The DAC requires a 24bit word containing the 12bit co-ord data, 3 bits for the control register and 3 more for the address register, per co-ordinate - i.e it needs 48bits per point.
The SPI is quick, each 24bit word is clocked out in ~8us...the x and y point takes ~28us.

So how does it perform?
I hooked it up to my scope and using CAMVO's routine for calculation the X and Y co-ords 36 points per circle i get 76Hz....Not too shabby.:beer:
At 72 points "scan" speed is 38hz. The limiting factor is the on the fly tri calculation.

It would be intersting to see if I could decode a ILDA file, the tiny ATMega memory is a problem, but maybe a SD card would be fast enough as these use the SPI interface too.
But for me, writing software is like swimming in treacle:yabbem:

36 points.
ds0005.png


72 points
ds0006.png


I might see if I can get it connected to my old G120 scanners, see what it looks like using proper photons:D

ATB
MM
 
Hi MB,
I don't want to hijack Camvo's thread any more than I have done, but I'm using a ATmega 328 on a breakout board running at 16Mhz - the SPI clock I think is running about 4Mhz.

Camvo has the better route as the Due has the on-board DACs.
He'll be able to write the data to these using just a few instructions / clock cycles as the DAC register is in effect just a memory address.
It will be "well fast".
Still, it'll be interesting to see how far the little AT328 can be pushed. I'll start another thread if I get my scanners powered up.
ATB
MM
 
You just hijack away Multimode. :p

As long "we" can solve this problem, I do not mind.
It would be for everyone's benefit. (I hope.)

I will order the Arduino Due this evening.
Expected delivery on Wednesday or Thursday.

I have a business trip to Germany and Switzerland coming up tomorrow.
Hope to be back on Friday.
 
Multimode's post reminded me that I have a MCP4922 DAC in my parts box.
I bought it some time ago when I bought the parts for the harp.

That (dual, 12bit) DAC has also a LDAC funtion.

No idea of how to implement it though.

Found the below code on the web:

But I do not see the LDAC implementation in this code.

If I understand the datasheet of the MCP4922, the values (X and Y) are written to the DAC and kept there until the LDAC pin is set to LOW and then the output voltages will be updated.

Do I understand this corectly?

Code:
/*
  MCP4922 test
  outputs steadily rising voltages through both DACs
  
  Steve Woodward, 2010
  most code borrowed from
  http://mrbook.org/blog/2008/11/22/controlling-a-gakken-sx-150-synth-with-arduino/
  
  connections
  ====================================================
  
  +5v           > 4922 pin 1
  Ard pin 10    > 4922 pin 3   (SS - slave select)
  Ard pin 13    > 4922 pin 4   (SCK - clock)
  Ard pin 11    > 4922 pin 5   (MOSI - data out)
  Ground        > 4922 pin 8   (LDAC)
  +5v           > 4922 pin 11  (voltage ref DAC B)
  Ground        > 4922 pin 12
  +5v           > 4922 pin 13  (voltage ref DAC A)
 
 
  4922 pin 14 DAC A > 1k resistor > synth CV in
  
 */
 
 
// MCP4922 DAC out
#define DATAOUT 11//MOSI
#define DATAIN 12//MISO - not used, but part of builtin SPI
#define SPICLOCK  13//sck
#define SLAVESELECT0 10//ss
 
int i = 0;
 
void setup() {
  SPI_setup();
  Serial.begin(9600);
}
 
void loop() {
 i++;
 Serial.println(i);
 write_note(i);
 if(i>=4096) {
  i=0; 
 }
}
 
void write_note(int i) {
  write_valueY(i);
  write_valueX(i);
}
 
 
 
 
// **************************************************
// SPI for DAC
 
void SPI_setup(){
 
  byte clr;
  pinMode(DATAOUT, OUTPUT);
  pinMode(SPICLOCK,OUTPUT);
  pinMode(SLAVESELECT0,OUTPUT);
  digitalWrite(SLAVESELECT0,HIGH); //disable device
 
  SPCR = (1<<SPE)|(1<<MSTR) | (0<<SPR1) | (0<<SPR0);
  clr=SPSR;
  clr=SPDR;
  delay(10);
}
 
// write out through DAC A
void write_valueX(int sample)
{
  // splits int sample in to two bytes
  byte dacSPI0 = 0;
  byte dacSPI1 = 0;
  dacSPI0 = (sample >> 8) & 0x00FF; //byte0 = takes bit 15 - 12
  dacSPI0 |= (1 << 7);    // A/B: DACa or DACb - Forces 7th bit  of    x to be 1. all other bits left alone.
  dacSPI0 |= 0x10;
  dacSPI1 = sample & 0x00FF; //byte1 = takes bit 11 - 0
  dacSPI0 |= (1<<5);  // set gain of 1
  digitalWrite(SLAVESELECT0,LOW);
  SPDR = dacSPI0;			  // Start the transmission
  while (!(SPSR & (1<<SPIF)))     // Wait the end of the transmission
  {
  };
 
  SPDR = dacSPI1;
  while (!(SPSR & (1<<SPIF)))     // Wait the end of the transmission
  {
  };
  digitalWrite(SLAVESELECT0,HIGH);
  //delay(2);
}
 
// write out through DAC B
void write_valueY(int sample)
{
  // splits int sample in to two bytes
  byte dacSPI0 = 0;
  byte dacSPI1 = 0;
  dacSPI0 = (sample >> 8) & 0x00FF; //byte0 = takes bit 15 - 12
  dacSPI0 |= 0x10;
  
  dacSPI1 = sample & 0x00FF; //byte1 = takes bit 11 - 0
  dacSPI0 |= (1<<5);  // set gain of 1
  
  digitalWrite(SLAVESELECT0,LOW);
  SPDR = dacSPI0;			  // Start the transmission
  while (!(SPSR & (1<<SPIF)))     // Wait the end of the transmission
  {
  };
 
 
  SPDR = dacSPI1;
  while (!(SPSR & (1<<SPIF)))     // Wait the end of the transmission
  {
  };
  digitalWrite(SLAVESELECT0,HIGH);
  //delay(2);
}
 
Last edited:
You just hijack away Multimode. :p
As long "we" can solve this problem, I do not mind.
It would be for everyone's benefit. (I hope.)
I will order the Arduino Due this evening.
Expected delivery on Wednesday or Thursday.
I have a business trip to Germany and Switzerland coming up tomorrow.
Hope to be back on Friday.

Hi Camvo,

That's great :beer:

I've been mucking about with PROGMEM.
This stores the point data in program memory instead of RAM.
So with 32k (-the program) there should be space for a few decent frames.

I drawn out a "LASER" logo - it has 492 points, the ATmega can process this at 38hz, which is plenty fast enough - I recon you could add another 200 points or so and still get well over 20hz which would still be flicker free.

I have some noise on the output which is prob due to the breadboard layout:thinking:

The Due is going to eat this - ARM coretex M3 running at 84Mhz:drool:

ATB
MM

492 points at 38hz
ds0005.png
 


Back
Top