Creating two independent 10bit DAC from three PORTS on MEGA32A

Go To Last Post
87 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello guys, I am trying to do a software solution for hardware that I have recently built. Now I am struggling with the DACs. I have two of them on a PCB, by using PORTB, PORTC and PORTD. What I am looking for is a SW solution that will allow me to create a variable called X and Y, which I will be able to set independently the value of X or Y to 0-1023 (which will result as a voltage on my DAC, which is currently a simple R2R ladder with some AA filter). I was reading the whole topic http://www.avrfreaks.net/forum/s..., but I am not really clever from it :D. Can yomeone please show me an example exactly for this? I can do it by myself but it is for my work and now I do not have time to play and explore, so if someone can give me a code example with some explanation, I would really appreciate it. Also, I need on PORTB one pin for laser TTL controlling (it is laser projector, X galvo, Y galvo and a laser module with TTL).

Thanks a lot guys!!!

 

Actual connection:

Last Edited: Sat. Jun 3, 2017 - 02:00 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

 

How to embed images in your post so that we can see them:  http://www.avrfreaks.net/comment...

 

Like this:

 

 

Yeayer wrote:

 it is for my work

So is there a fee payable?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yeayer wrote:
a simple R2R ladder

If it's just a simple R2R ladder, is there really any point in making it 10-bits?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Okay, I will edit.

No I mean it is for my work, my own work that is a laser projector, i should use the word "project", I work as a car electronis serviceman, there is no need for a laser projector in this :D. I have it for my project that is a speaker with a laser projector, that will react to sound.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Is it not as simple as something like:

send_DAC(uint16_t x, uint16_t y) {
    PORTA = x & 0xFF; // bottom 8 of x to A
    PORTB = y & 0xFF; // bottom 8 of Y to B
    // and here comes the "tricky bit"...
    // this takes the top 4 of x and outputs as botton 4 to C
    // and the top 4 of Y and outputs to top 4 of C
    PORTC = ((x >> 8) & 0x0F) | (((y >> 8) & 0x0F) << 4);
}

EDIT: didn't see the pictures when I wrote that so my bit splitting is wrong - but the idea is the same.

Last Edited: Fri. Jun 2, 2017 - 12:56 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I doubt if you really need 12 bits of resolution. 8 bits will be plenty good enough for most applications.
.
Your schematic is complete pants. Life is much easier if you have the msb in your R2R ladder corresponding to msb in a PORT.
Currently your ladder msb is corresponding to lsb in a port. The calculations will be very complex.
.
Line up port bits in the correct order and the mapping is easy. e.g. two statements per X and Y.
.
David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes, I need a better resolution, 8bit can not write text in nice fonts without distortion, I tried it by 10bit (just by writing PORTC=0b00101011; PORTD=0b01110101;_delay_ms(1); etc...) and it was very nice.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

David, the MSB corresponds to MSB. What you can see is actually only the numbers of connector pins...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

OK, having seen the pictures here's attempt 2:

send_DAC(uint16_t x, uint16_t y) {
    PORTC = (PORTC & 0xFC) | (x & 0x03); // bottom 2 X to C
    PORTD = (x >> 2); // top 8 of X to D
    PORTB = (PORTB & 0F0) | (y & 0x0F) // bottom 4 Y to B
    PORTC = (PORTC & 0x03) | ((y >> 4) << 2); // top 6 Y to C
}

PS as you may have spotted this is really just about learning what &, | and << or >> do !

Last Edited: Fri. Jun 2, 2017 - 01:10 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Cliff's code is very straightforward.
You could combine the two PORTC statements. The compiler will produce efficient code.
.
David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

david.prentice wrote:
You could combine the two PORTC statements.
Quite - I just split the X and Y stuff to hopefully give a clearer picture of what was going on ;-)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You might want some sample and holds on the output of the dacs - especially the one with the split ports as you might get some funky values output otherwise when one set of port bits are written then the next set.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Would that really be the case in the odd microsecond (or fraction thereof) between one PORT write and the next?. But agree it might be best to read the current port states up front, prepare the data updates going to each then just do three straight PORTx=n writes at the end so there's nothing but the time of an OUT between each.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If you don't want to use shifts, maybe something like this works, using an union and bit fields. It's more indirect, so it's slower, larger and uses RAM memory, but maybe it's clearer. I'm sure all the bit positions are wrong, but this is just to get the idea.

 

union {
	struct {
		uint8_t d_val;
		uint8_t c_val;
		uint8_t b_val;
		uint8_t a_val;
	} port;
	struct {

		uint32_t x :10;
		uint32_t y :10;
		uint32_t unused :12;
	} coord;
} axes;

int main (void) {
	axes.port.b_val=PORTB;   //save previous state of unused bits in port B
	axes.coord.y=950;
	axes.coord.x=1000;
	PORTB=axes.port.b_val;
	PORTC=axes.port.c_val;
	PORTD=axes.port.d_val;
}

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Go on.   Cliff's solution could not be much clearer.   And will be pretty efficient too.

send_DAC(uint16_t x, uint16_t y) {
    PORTC = (x & 0x03) | ((y >> 4) << 2); // bottom 2 X to C, top 6 Y to C
    PORTD = (x >> 2);                     // top 8 of X to D
    PORTB = (PORTB & 0xF0) | (y & 0x0F)    // bottom 4 Y to B
}

This sort of "wiring" is done once.    The compiler handles shifts pretty well.

Yes, you could calculate into shadow registers.   Then all 3 PORTs can be written with 3 OUT instructions.

 

Life could be arranged a little better.   e.g. 8-bits of y in PORTC, 8-bits of x in PORTD.   Odd bits in PORTB.

Incidentally,   writing a "bus" to random PORT bits can involve a lot of masks and shifts.    An AVR can do 1-bit, 4-bit, 8-bit shift reasonably well.   Other shifts can be painful.

 

In contrast,  an ARM has a barrel-shifter.    The C expressions look horrible.   The compiler does the actual operation within nanoseconds.

 

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

1)  Why is this in the Xmega forum?

1a) If you use an Xmega, most models have two channels of DAC built-in

2)  By the time you are done, a Microchip MCP4922 family http://ww1.microchip.com/downloa... has two channels and is a buck a channel in quantity.  And not to dear in low quantity; less than 3 bucks.  [IIRC Microchip has a pretty good sampling policy...]

Other variations have onboard reference and cost a quarter more; lower res a bit cheaper:

 

It comes in a variety of packages including DIP.

 

When we apply it, we have a following op amp anyway to get a bit more drive.  At that point you can use the op amp to add gain if you need e.g. 10V output.

 

3)  Extra credit:  Run a line back from the DAC output (the raw, or the amplified with suitable divider) into a feedback ADC channel for calibration, short-circuit detection, and similar.

 

4)  That series has been discussed a number of times here, and driver code has been posted.

E.g. http://www.avrfreaks.net/comment...

http://www.avrfreaks.net/comment...

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

Last Edited: Fri. Jun 2, 2017 - 08:52 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Before contemplating a software solution (an oxymoron, I know), I always recommend searching for a hardware solution first.   Here is an eBay listing for 12-bit serial DAC ICs selling for $1.60 each:

http://www.ebay.com/itm/25pcs-DA...

 

Sure, you have to buy 25, but are you making at least ten of these devices?   If not, then a software solution is not recommended since the development period is long to be spread out over so few units to be economically viable.  And to be using an R-2R resistor ladder for a 10-bit DAC?   One could cry.

 

But, sure, it can be done. Anything can be done. In software.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Simonetta wrote:
And to be using an R-2R resistor ladder for a 10-bit DAC?   One could cry.

Indeed - see #3.

 

And just a "simple" R-2R ladder, at that!

frown

Last Edited: Fri. Jun 2, 2017 - 10:27 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'm puzzled. This is in the XMega forum but you say Mega32A. Answers could be quite different for XMega!

 

Jim

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Forget about conveniently making 12 bit or really even 10 bit dacs---your resistor mismatching will render the performance rather poor.  You can work around that & buy expensive matched resistor networks to build your own dac...but why not just  buy a cheap dac, where the important matching & characterization (including over temperature) has been done for you? 

When in the dark remember-the future looks brighter than ever.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Okay, first of all, sort of thank you all guys for responses, clawson especially, because he almost gave me the thing I am looking for. Sorry for wrongly posting this in Xmega forum, if a mod could please move this in ATmega forum, I would appreciate it. 

Another thing is - I know this a huge problem of any forum, I just dont have mental energy to explain why I did not use a microprocessor already with built in better DAC, etc., why I did not use already completed stuff. The reason is pretty simple - I am

trying to understand C and basically the ATmegaXX MCUs are the best for me to learn, I already have a programmer for it, and I am a newbie in this. So thats why, mr. theusch, I dont know even how to use operators, I have read a lot of stuff in books and on web too,

but simply it is too hard for me to understand how you can guys put together such a code including something like struct (which I do not even know what it is), and you just posted here D/A with serial communication (I wont be even able to send data to it with my experience,

thats why, even an easy few latch and enable pins on parallel DAC would make me overheat my brain for a few days I think. So I have chosen finally, when I am hardly stuck, to ask on a forum about programming AVRs for a first time. Until now I have learned by myself how to

set ports, how to use ADC (which was the hardest for me), and now I am struggling with a thing called bit mask. So I asked for a piece of a code, that will work with my HW, so I can learn why is there this and that and how it works together to learn new stuff. I would really like

to learn this, but even after reading (I am not kidding) about maybe hundreds of threads on web and maybe two complete books about programming in C, I am simply not able to recognize where I can use functions or operators. I am basically learning how something works by just

rewriting the same code until it somehow starts working, using oscilloscope, and when it finally works I immediately start to make the code more complex and bigger and then I am happy it somehow works. But now, I am just stuck. I dont know what to do and how to make this thing work. So, again, if anyone can give me a tutorial that will exactly work with my HW, it will help me the best. As soon as I try to use and rewrite someones solution, first thing is that it does not fit my HW, or it is without explanation so I  dont know how to edit it. I know asking for this is

not good, as soon as I am probably asking guys that are payed astronomic money for their work and I want something for free, but I dont really know any other solution, as I said, I spend a lot of hours, most likely tens of hours googling and trying with no result, that is why I posted it there. Sorry, and thanks.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Yeayer wrote:
but simply it is too hard for me to understand how you can guys put together such a code including something like struct
Then to be honest, before learning to program micro electronics you should first dedicate time to learning a programming language. If that is to be C then you will do better using a PC based compiler to write PC programs. It's much quicker/easier to build/run/debug using a PC development system and you can use that to learn the basics of C.

 

For microelectronics you use some bits of C (especially the bitwise operators) much more than you might find in average PC programs so concentrate your learning in that area to prepare you for using MCUs.

Yeayer wrote:
But now, I am just stuck. I dont know what to do and how to make this thing work.
Well you haven't done yourself any favours in the way you have things wired up. As others have said, start with 8 bits (so everything can be done in one PORT) and either use an R-2R package, a parallel DAC or perhaps even consider using a serially interfaced DAC that maybe uses SPI or I2C(TWI) to connect to the MCU.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I am using Atmel Studio and I have succesfully made a stepper motor driver with its speed being controlled by a potentiometer, which is a thing that took me like 4 days of learning, and I have programmed the ADC only using the datasheet of ATmega MCU, so I have already done this. My laser projector is currently using 2x8bit DAC with R2R ladder, which is good, but I need it to be mroe accurate. Simply, the steps are too big. I know what you mean by your reply, but I simply have this exact problem and if anyone can help me like clawson did, that is what I am looking for. I am not looking for better solution or an IC DAC, I am looking for a tutorial and help, so I can learn something, after I can get a simple R2R ladder DAC with a simple MCU program working, then I can move on. I have done this hard for me enough to learn new stuff, not to easily buy even a whole projector on ebay, or a working DAC. I want to learn C. As I wrote, I have tried reading a lot of stuff about C, but without practical use I can not understand it.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yeayer wrote:
if anyone can help me like clawson did,
I am clawson ;-)

 

Well since you think you can run before you can walk can I suggest you take a few tentative steps in this direction? ....

 

http://www.avrfreaks.net/forum/t...

 

But boolean algebra is not something you are going to just pick up in 5 minutes. You need to see the operation of AND, OR, EOR as the bits in two registers are combined. For that I might even suggest looking at Asm and stepping opcodes in the Studio simulator so you can see the before/after situation in register contents when doing those operations.

 

Later they just become the &, | and ^ operators in a C program.

 

Another approach is to use those in C then debug the "goto disassembly" view of the C where you can see both the highlevel C and the low level opcodes and once again you can step one opcode at a time to see what AND/OR/EOR achieve in the simulator.

 

It will also be necessary to learn about << and >> (in Asm LSR, LSL, ROR, ROL).

 

Wish I could remember back to 1981..84 when I did boolean algebra at university. We had a terrific text book that explained it all - would be a great way to learn but that was 35+ years ago and I cannot remember the name of the book I used to learn this stuff formally.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Oh, sorry, got lost in my own answers... The link you have send is what I have read like 20 times. I got it how boolean algebra works, but I am not able to implement it in a code. What makes me the biggest problem is the bit shifting. 

So, now, if I have PORTD as the lower 8 bits of the whole 10 bit xvar, I will have to do something like PORTD equals variable x masked by 0b0011111111? And then the PORTC equals variable x masked by 0b1100000000 and shifted down 8 times and it also equals variable y masked by 0b0000001111 shifted up 2 times?

Last Edited: Mon. Jun 5, 2017 - 08:34 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Why are some people afraid to try stuff? After a few tries you should get the idea - it's not brain surgery.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yeayer wrote:
I will have to do something like PORTD equals variable x masked by 0b0011111111?
Well you  can and I often will use:

PORTD = x & 0xFF;

to emphasise to the reader that I fully intend to only take the lower 8 bits. However I would get the same effect if I simply wrote:

PORTD = x;

because of the C rules of promotion and truncation. The C compiler "knows" that the left hand destination here is 8 bits wide (that is part of how "PORTD" is defined) so the compiler will already be truncating x (that is wider than 8 bits) to just take the lower 8 bits to assign to the 8bit wide destination anyway.

 

However I deliberately use "& 0xFF" to emphasize to the reader that I know this is happening. When I add that "& 0xFF" the compiler is not going to generate any additional code as it is already effectively doing that anyway so this is just a subtle hint to the code maintainer who is trying to read what I did here.

And then the PORTC equals variable x masked by 0b1100000000 and shifted down 8 times and it also equals variable y masked by 0b0000001111 shifted up 2 times?

As Kartman says, don't be afraid to try this stuff. When you read a line like:

    PORTC = (PORTC & 0x03) | ((y >> 4) << 2); // top 6 Y to C

just break it down into pieces to work out what is happening here. Again, when I write code I probably make more use of () than absolutely necessary. That's for 2 reasons. One is that I can never remember the order of precedence of the C operators but the other is to actually say to the reader "this bit first, then this, then this..."

 

Reading right to left the first sequence is:

(PORTC & 0x03)

which is going to read 0bXXXXXXXX that is already held in "PORTC" and AND this with 3 (0b00000011) so the result will be 0b000000XX so only the bottom 2 bits in C are kept in tact and the other 6 are wiped to 0. Moving on there is:

(y >> 4)

So "y" may well be 16 bits wide with the bottom 10 bits active. This moves stuff 4 places to the right so the bottom 4 bits are lost and all that remains are the upper 6 active bits (for safety I suppose I should have used an & mask to remove anything "above" those 6 but I am trusting the provide of "y" that only 10 bits are being passed in. So 10 moved 4 places right leaves 6.

 

But I now need those 6 in the upper 6 not the lower 6 bits of the 8 that make up PORTC so then I apply:

(current_value) << 2

So that moves the 6 active bits to the upper 6 of the 8. Finally:

PORTC = existing_PORTC_masked | active_6_bits;

is performed so the 0b000000XX are combined with the 6 bits from "y" to make 0byyyyyyXX and that is written back to PORTC.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Cliff has written an excellent explanation.

 

Don't be afraid of trying things.    I suggest you re-write the complex expression with pencil and paper.

Split it into individual operations.    Re-write a hexadecimal expression as a binary expression e.g 0b0101100 and make sure that you line all the bits up.

 

Just like you do with dollars and cents when adding up a bill.

 

It also makes it easy to see what happens when you shift left or right.

 

I certainly write it down on paper when bit shifting and bit masking is complex.   I suspect that Cliff does too.

 

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
        PORTD=(x & 0b0011111111);
		PORTC=x>>8;
		PORTB=0xFF;

Actually, this is working and my X axis is going full swing 0-5V.... Clawson thank you SO MUCH

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You're referring to stuff being hard to learn, but yet you got a (microstepping, it sounds like) stepper motor driver out the hangar in a few days. That is impressive and you should be proud!

 

With that said: One point ppl are trying to make above is that if you're up over your ears with "hard-to-learn" stuff then the least hard-to-learn way re a DAC with better resolution might well be a dedicated DAC driven from your AVR. One hint/point above is that an R2R DAC will have the resolution you crave - but it will be very hard to get the accuracy you probably also want. Do not confuse resolution and accuracy (a common mistake).

 

You must also understand that ppl here likes to help, but are not very interested with solutions that they (by their experience etc) quickly deem very awkward. Somewhat jokingly: If you went to a gourmet forum and aqsked about eating through your ear standing on your head, then you'd rather get advice on other more common ways to eat than help with your envisioned solution.

 

Suppose no-one has ever done what you ask because they realise from the beginning that it will be a bad or not-at-all working solution. Then why should they put the time in to investigate a solution that is, with as high degree of probability, in vain? (You have to realise that for many problems here we don't just pull a ready-to-run solution out of a hat - we give the problem a go and work/solve it, if even just a sketchy solution.)

 

Consider the suggestions given above, before just rejecting them because they are not on your envisioned path.

 

If you do get the R2R DAC working, then please report back on the results.

 

Adding to the possible inaccuracy of a R2R with many steps, there is also the problem that stepper motors often are not very good at high-resolution micro-stepping. Mechanics, inaccuracies in how the magnetic fields behaves/forms etc.. You can only get that many microsteps out of a stepper motor before it starts getting meaningless. Five microsteps per step, or thereabouts..

Happy 75th anniversary to one of the best movies ever made! Rick Blane [Bogart]: "Of all the gin joints, in all the towns, in all the world, she walks into mine."

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks a lot. I am kinda experienced in making HW, I made a lot of audio amplifiers, thing like coilguns with few optical stages, VU meters using 10 pcs of 3914, VU meters with CCFLs, ambient car lights, even a small and not really strong but working xray. Now I kinda realised

that with an MCU i should just multiplex these 100LEDs on LM3914 usind 20 pins, not making a huge PCB with quadrillion routes :D. So I started learning C in Atmel Studio using ATmegas (I have done few small easy projects with 8, 16A, 32 and 328). 

By the way, now my code looks like this and it is kinda not working, I know I am doing something wrong but do I have to mask the variable or not? And how to combine these two masks? I can not really understand what I have to shift first, and also where, because I feel like I mask the PORT and then I just move the mask, the variable, the port and maybe with this messy code I am moving some buildings over my house without knowing it.

        PORTD= (x & 0b0011111111);
        PORTC= ((PORTC & 0b00000011) | ((x & 0b110000000000)>>8));
        PORTC= ((y & 0b0000111111)<<2);
        PORTB= 0b00010000;

EDIT: for now please ignore PORTB, set it like this to have y axis in the center and to have the laser pin output still on so I can see on the wall how the mirrors are moving

Last Edited: Mon. Jun 5, 2017 - 09:38 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Step this in the debugger/simulator - see what's actually happening with any bit patterns you feed in to it.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok guys, final question. I got it somehow almost working (big thanks clawson, your explanation in #27 cleared it for me alot. But, now with this code, it looks like it is messing with using one port for two different variables, so as soon as I delete one of the PORTC equals, x or y works great, but not together. How can I set e.g. bits 0 and 1 in PORTC without changing others? Now, if I understood it in the right way, the bit mask only does a simple AND between the variable and port setting, but when somewhere is 0 in bit mask, it will set the PORT there to 0, or not? because now it looks like the PORT can only react for x or y, but can not change only a part of itself... -_-

                PORTD= (x & 0b0011111111);
		PORTC= ((x>>8)&0b00000011);
		PORTC= ((y<<2)&0b11111100);
		PORTB= ((y>>6)&0b00001111);

EDIT: On the image you can see what I am getting on a scope, Y is missing some LSB, that is why it is distorted, and the X is missing MSB, the two written in PORTC i guess.

Last Edited: Mon. Jun 5, 2017 - 11:30 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I will say that logic this is a good solution, but it will make a lot of noise on the outputs.

 

Two main rules :

1. never update a hole port 2 times

2. when values depends on each other on more than 1 port, make the writes close in time.

 

And the 2. write to portc delete the bits from x!

 

you should make 3 temporary values and THEN write those to the ports. 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks, I was thinking that, but how can I write it to avoid deleting x bits by writing in the y ones? I can create variables and then load them to ports, but how?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

something like this (have not checked your IO's):

 

        tempD= (x & 0b0011111111);
        tempC= ((x>>8)&0b00000011)+((y<<2)&0b11111100);
        tempB= ((y>>6)&0b00001111);
        PORTD=tempD;
        PORTC=tempC;
        PORTB=tempB;

 

 

Add:

For cleaner code the + should be |   (logic or) but in this case it's the same. 

Last Edited: Mon. Jun 5, 2017 - 11:42 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Follow sparrow's advice but just to say that the "simple" solution to:

		PORTC= ((x>>8)&0b00000011);
		PORTC= ((y<<2)&0b11111100);

is simply

		PORTC = ((x>>8)&0b00000011);
		PORTC |= ((y<<2)&0b11111100);

The '|' in the second is OR and effectively means "add this bit to what is already there". However note that | can only ever set additional 1 bits it cannot clear any bits that are already 1 back to 0. So you need to ensure the destination bits are already cleared to 0 before you OR in the new value.

 

But go with what Sparrow shows, it's effectively putting in to practice what I suggested in #13 anyway....

But agree it might be best to read the current port states up front, prepare the data updates going to each then just do three straight PORTx=n writes at the end so there's nothing but the time of an OUT between each.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ups did't read the hole thing :(

Last Edited: Mon. Jun 5, 2017 - 12:29 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I dont know how, but merging the two PORTC equals with + (I used & instead of+) works quite good!!! Thanks a lot!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You really need to learn your logic! 

in this case + and | give the same but & don't!

 

 

 

 

Last Edited: Mon. Jun 5, 2017 - 12:32 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

sparrow2 wrote:
You really need to learn your logic!
+1

 

OR and + are sometimes equivalent as long as the position of the bits in the two inputs do not overlap but & is a completely different kettle of fish.

 

& is generally used for clearing bits so if you & together the two halves of PORTC that have no overlapping bits the result is bound to always be 0.

 

Like I say, try and find a good book or tutorial on boolean algebra and study it (work through some examples - the AVR simulator is actually a great place to see this stuff in action).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

That is not about finding a good book. Now I have inspected it in AS debugger and I think now I understand how it works :). As I said, I just need an example that fits my project, and then I can modify it, see what happens and therefore understand how it works.

Thank you all guys, you helped me a lot!! I was really stuck there, even after reading a lot of stuff, but there you can see when you and sparrow2 wrote exact codes, now I just re-writed my code using your modified codes you have posted here and it works, I have exactly fitted my HW and I have by myself added anothe mask for one pin for laser :). Thanks again!!! full code here: 

#include <asf.h>
#define CSHIFT 35

int main (void)
{
DDRB=0xFF;
DDRC=0xFF;
DDRD=0xFF;
int x=0;
int y=0;
int lsr=0;
unsigned int i=0;
while (1)
	{	
		PORTD= (y & 0b0011111111);
		PORTC= ((y>>8)&0b00000011)+((x<<2)&0b11111100);
		PORTB= ((x>>6)&0b00001111)+((lsr<<4)&0b00010000);
		
		if (i<500)
		{
			x=269;
			y=110;
			i=i+CSHIFT;
			lsr=1;
		}       //And there I just put another coordinates, using CSHIFT to define the speed of the change between coordinates (the bigger it is, the faster it reaches the number 500 and another coordinate will be shifted)

Working fluently and precisely, a lot better than 8bit, later I will send old picture of projected image vs the actual one. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Just to show why that code is bad:

 

Here is your code (x y lsr are volatile and it's compiled with -O2).

				PORTD= (y & 0x3f);
  7a:	8b 81       	ldd	r24, Y+3	; 0x03
  7c:	9c 81       	ldd	r25, Y+4	; 0x04
  7e:	8f 73       	andi	r24, 0x3F	; 63
  80:	82 bb       	out	0x12, r24	; 18
				PORTC= ((y>>8)& 0x03)+((x<<2)& 0xfc);
  82:	8b 81       	ldd	r24, Y+3	; 0x03
  84:	9c 81       	ldd	r25, Y+4	; 0x04
  86:	2d 81       	ldd	r18, Y+5	; 0x05
  88:	3e 81       	ldd	r19, Y+6	; 0x06
  8a:	89 2f       	mov	r24, r25
  8c:	83 70       	andi	r24, 0x03	; 3
  8e:	94 e0       	ldi	r25, 0x04	; 4
  90:	29 9f       	mul	r18, r25
  92:	80 0d       	add	r24, r0
  94:	11 24       	eor	r1, r1
  96:	85 bb       	out	0x15, r24	; 21
				PORTB= ((x>>6)& 0x0f)+((lsr<<4)& 0x10);
  98:	2d 81       	ldd	r18, Y+5	; 0x05
  9a:	3e 81       	ldd	r19, Y+6	; 0x06
  9c:	89 81       	ldd	r24, Y+1	; 0x01
  9e:	9a 81       	ldd	r25, Y+2	; 0x02
  a0:	02 2e       	mov	r0, r18
  a2:	23 2f       	mov	r18, r19
  a4:	00 0c       	add	r0, r0
  a6:	22 1f       	adc	r18, r18
  a8:	33 0b       	sbc	r19, r19
  aa:	00 0c       	add	r0, r0
  ac:	22 1f       	adc	r18, r18
  ae:	33 1f       	adc	r19, r19
  b0:	2f 70       	andi	r18, 0x0F	; 15
  b2:	82 95       	swap	r24
  b4:	92 95       	swap	r25
  b6:	90 7f       	andi	r25, 0xF0	; 240
  b8:	98 27       	eor	r25, r24
  ba:	80 7f       	andi	r24, 0xF0	; 240
  bc:	98 27       	eor	r25, r24
  be:	80 71       	andi	r24, 0x10	; 16
  c0:	82 0f       	add	r24, r18
  c2:	88 bb       	out	0x18, r24	; 24
  c4:	da cf       	rjmp	.-76     	; 0x7a <main+0xe>

As you see in <80> you output the first 8 bits of y but not before 96 (15clk later) you write the last 2 bits.

 

so if y don't change everything is fine but if y was 255 last time and is 256 this time, the y DAC will have the value of 0 for about 1 us before it get the value of 256.

at least with temp variables it will be 1/16 of that.

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
... or perhaps even consider using a serially interfaced DAC that maybe uses SPI or I2C(TWI) to connect to the MCU.
Or PWM between the mega32A and the DAC at 25KHz max for 10 bits.

mega32A has 4 PWM channels.

Linear Technology's PWM DAC are 0.65mm pitch so won't be easy to prototype and are significantly more expensive than what's in

http://www.avrfreaks.net/forum/creating-two-independent-10bit-dac-three-ports-mega32a#comment-2178741

 


Linear Technology

Accurate, Fast Settling Analog Voltages from Digital PWM Signals

Mark Thoren - Staff Scientist
Chad Steward - Design Manager

Mar 17th 2015

http://www.linear.com/solutions/5683

...

This is a simple, practical technique if the analog signal’s performance requirements are not too stringent, as only one output pin is required and the code overhead is very low when compared to a digitalto- analog converter (DAC) with an SPI or I2C interface.

...

http://cds.linear.com/docs/en/product-selector-card/2PB_2645f.pdf (PWM DAC page 1, page 2 is the DAC selector table)

 

"Dare to be naïve." - Buckminster Fuller