![]() |
Forum Index : Microcontroller and PC projects : Playing around with bits....
Author | Message | ||||
Grogster![]() Admin Group ![]() Joined: 31/12/2012 Location: New ZealandPosts: 9610 |
Hi folks. ![]() In the stereo project that jman is helping me with, he wrote most of the code to manipulate the bits of the data byte for any address that you send off to the pre-amp chip, but I would like to understand how this actually works. Take the following snippet from the manual: ![]() As you can see, this byte consists of several things you can adjust, those being the input source selector, the input gain, and the AutoZero feature. I understand how all this changes to get you what you want, but what I DON'T understand, is the mathematics behind how you manipulate the bits of the byte to get the final byte you send off to the device with the settings you want. Take for example, the case of wanting SE1 input, 3dB input gain and AutoZero off. This would result in a final byte of &B10011100, or 9Ch(156 decimal). That's fine, and I follow all that just fine, but the problem I am having is in working out HOW you combine the values into the one byte. jman used XOR, but I have played with XOR at the command prompt, but it does not render the results I expect, I am obviously not understanding how XOR works as well. I post this here, rather then pester jman directly, as I thought it might make a useful public discussion, and a chance for others to learn the same thing I am trying to learn etc, etc, etc... So, getting back to the above example, and going on what I do understand about how binary numbers are powers of two, you therefore have the following values for the byte: AutoZero=80h(128 decimal) Gain(3dB)=18h(24 decimal) Input(SE)=04h(04 decimal) Adding these together, we correctly come to 9Ch(156 decimal), and all this is fine, and I follow all that. WHERE I AM LOST: Combining the numbers SIMPLY. You can, naturally, add the numbers up, but if you have to set bit7 in one command, and bits 4 & 5 in another command, and then COMBINE both those into ONE byte, WITHOUT upsetting the bit-positioning of any previous command - this is where I am lost. Not sure I am explaining it that well, as I don't understand the mathematics involved, so am probably using the wrong terms, but hopefully everyone can see what I mean. A very simplistic am mathematically incorrect way of demonstrating the above is that you have two bytes in the form of A=&B10000000 and B=&B00011000 - how do you combine those so that you end up with a single byte equal to &B10011000? A XOR B does NOT return the correct result(298h or 664 dec), so I am unwilling to trust this blindly, even though this is how jman is doing some of it. Another example might be three(or more) values such as in this example: A=&B10000000 B=&B00011000 C=&B01000000 "Adding" together, I would need the result to be &B11011000. This bit shifting stuff has me totally confused at the moment. I know what needs to happen, but I don't understand what mathematics need to happen to do it. Can anyone help me understand how to do this? EDIT: Writing things down seems to help clarify to some extent. I think my problem is that I am not remembering to stay in the correct decimal value of things. Take the gain control in the chart above. I see this as 1-15(0001-1111), so adding 3 to the value of the byte DOES NOT render the correct results, as the bits are in the wrong place. Although there are 15 numbers(001-1111), the decimal value range is actually 8-120 using those four bits, but I want to show this on the screen as 0-15dB, and am getting lost in the conversions needed. Smoke makes things work. When the smoke gets out, it stops! |
||||
TassyJim![]() Guru ![]() Joined: 07/08/2011 Location: AustraliaPosts: 6283 |
When working with bits it is best to use BIN as you are doing. You need to understand the basic BIT operations - AND OR and XOR AND, if both bits are set (1), the result is 1 OR if either bit is set, the result is 1 XOR if one bit is set (1) and the other not set (0), the result is 1 There is no 'carry' and the operation is done on each bit independently. try this code: A=&B10010000 B=&B00011000 C=&B01000000 PRINT BIN$(a,8) PRINT BIN$(b,8) PRINT BIN$(c,8) PRINT "" PRINT BIN$((a OR b),8) PRINT BIN$((a AND b),8) PRINT BIN$((a XOR b),8) PRINT "" PRINT BIN$((a OR b OR c),8) PRINT BIN$((a AND b AND c),8) PRINT BIN$((a XOR b XOR c),8) PRINT "" PRINT BIN$(((a AND b) XOR c),8) PRINT BIN$((a XOR (b XOR c)),8) All the BIN$ stuff just makes the code harder to follow but is need to see the results. When you start working with more than 2 numbers, use brackets so you are certain of the order in which the operations are performed. There are too many correct ways of doing it - it is the sort of thing that starts heated discussion. Jim VK7JH MMedit |
||||
WhiteWizzard Guru ![]() Joined: 05/04/2013 Location: United KingdomPosts: 2944 |
According to the table, shouldn't that be &B10011001 ![]() I haven't got to the end of your post yet, but hope this isn't the issue ![]() |
||||
Grogster![]() Admin Group ![]() Joined: 31/12/2012 Location: New ZealandPosts: 9610 |
Thanks - will experiment with your demo code. These are the results I got: ![]() I will play around more with your demo code. Still lost, but I will persevere. ![]() It would seem that what I need is the ? BIN$((A OR B),8) command? So therefore, A OR B should give me the combined result, yes? What if we throw variable C into the mix? Can you have something like ? A OR B OR C? I will experiment some more. Not meaning to start a heated discussion on the best way to do it. ![]() I just want to understand HOW, as I am still lost on this at the moment, and if I just let jman deal with that side of the code, I am not actually learning anything, and this kind of stuff is used on just about any I2C chip for the config bytes, so it is something I would like to understand. Smoke makes things work. When the smoke gets out, it stops! |
||||
Grogster![]() Admin Group ![]() Joined: 31/12/2012 Location: New ZealandPosts: 9610 |
Yes, it should - typo - sorry. ![]() Smoke makes things work. When the smoke gets out, it stops! |
||||
TassyJim![]() Guru ![]() Joined: 07/08/2011 Location: AustraliaPosts: 6283 |
For your volume, try this code snippet db = 15
dbBITS = db*8 PRINT BIN$((dbBITS),8) Ypu would then OR the resulting dbBITS with the other control bits to get the value to sent to the device. Try it with different values for db multiplying by 8 is the same as shifting left by 3 bits. 2*2*2 remember, the BIN$ stuff is just so that us mere mortals can see the number in binary. The computer doesn't care. "Can you have something like ? A OR B OR C?" See my first (amended) post . Jim VK7JH MMedit |
||||
Grogster![]() Admin Group ![]() Joined: 31/12/2012 Location: New ZealandPosts: 9610 |
Ahhhh - I think I am making slow progress. Some experiments: ![]() If I OR anything together, this would seem to put the bits where I need them. I don't know if this is just because of the way I have setup my example or not though. Smoke makes things work. When the smoke gets out, it stops! |
||||
WhiteWizzard Guru ![]() Joined: 05/04/2013 Location: United KingdomPosts: 2944 |
OK - there are many ways to get the end result - however, you have specifically asked about a 'simple' way of 'adding' the numbers. My approach would be (based on the example chart) to have three variables representing AutoZero (0-1), Input Gain (0-15), and Source (0-7). So each of these three variables take on only one of their possible values. The approach is then set/change any variable, then call one common sub to 'compile' the resultant byte. So to compile the resultant byte (call it x, and initially set x=0) the AutoZero value (0 or 1) needs to be multiplied by 128 (or shifted 7 bits left), and then OR'd with x (or added to x), the Input Gain multiplied by 8 (or shifted 3 bits left) and OR'd with x, and the Source left as it is and OR'd with x. If you now wanted to go from 3dB to 2dB you need to change ALL the relevant bits in the byte i.e. for gain, bits D3, D4, D5, and D6; while leaving all other bits (i.e. other functions) untouched. This is where I think you are after a 'simple' way to do it. Again, many ways to do this including masking, XORING, shifting. But I would simply call the same routine I outlined above which will then adopt any change in value in any of the three functions. The above approach is useful when you have a variable/feature that takes on a 'direct' binary value such as the input gain. So here, the binary range is 0000-1111 which represents a 'human' range of 0-15. The approach above allows you to keep a variable called InGain to a human readable number of 0-15 which makes the code nice and easy to read. However, all that said, if you several 'features' in a byte that have no 'human' meaning (typically one or two bits in the byte), I would store these as binary values. So in the above example, AutoZero would be &B10000000. Then this becomes like your 'A,B,C example you gave where all you need to do is OR the bytes together to initially compile the result (or add them together as you put it!). Now to change a 'section' of the byte without altering other functions/bits the approach I would use is a two step process: First to mask out (with AND), then OR the channge to get the result. So going from 3dB to 2dB: &B1 0011 001 Initial byte value (AutoZero, 3dB, SE1) &B1 0000 111 (mask out the function changing by ANDing with this) ------------ =B1 0000 001 B0 0010 000 (OR with the new Gain required) ------------ &B1 0010 001 (AutoZero, 2dB, SE1) Now define simple!!! ![]() |
||||
WhiteWizzard Guru ![]() Joined: 05/04/2013 Location: United KingdomPosts: 2944 |
Blimey, that took me a long time to type - been lots of posts since I started typing ![]() Hopefully it will make sense soon ![]() |
||||
JohnS Guru ![]() Joined: 18/11/2011 Location: United KingdomPosts: 4044 |
Quick tip: XOR is not used much. (Except in e.g. CRC calculations if you do any.) Another: to set a few bits (like the bottom 3 in your example) to a specific pattern, you often want to zero them out then OR in the pattern (the new setting). Deleting (zeroing) bits is an AND NOT. In this case you'd want to AND with NOT &B111. The idea of NOT is to invert each bit. So, you'd AND with &B11111000. It keeps all the bits where the 1s are and zeroes all the bits where 0s are. (In case MMBasic doesn't do NOT like this, you can make a function.) John |
||||
Grogster![]() Admin Group ![]() Joined: 31/12/2012 Location: New ZealandPosts: 9610 |
@ WhiteWizzard - Thanks for your long post, and it was very helpful too. I am inclined to agree with your way of thinking(as it is my way of thinking too), in that you have a sub to compile the byte. I too look at each separate parameter as numbers within the control range, and not the actual value of the bits within the byte - that was also a source of my confusion. @ everyone - I am going to run several other experimental test codes to help me understand this better. I will post back with any issues I have, and I expect to have some, as I am learning something new to me here..... Smoke makes things work. When the smoke gets out, it stops! |
||||
Chris Roper Senior Member ![]() Joined: 19/05/2015 Location: South AfricaPosts: 280 |
I respectfully disagree John ![]() XOR is probably the most used logic function in embedded applications, primarily for its ability to toggle one or more bits in a byte or a Port. Maybe not so relevant in MMbasic, but I use it often on the 8 bit PIC devices. Cheers Chris http://caroper.blogspot.com/ |
||||
Grogster![]() Admin Group ![]() Joined: 31/12/2012 Location: New ZealandPosts: 9610 |
UPDATE I have some simple code working now, and I think this is the way I will proceed forward - some of you will not agree with this method, but I can understand it when done this way. Here is a section of the ROHM processor manual: ![]() My experimental code: 'Amp-A-Mite 2A (Rohm processor) 'November/December 2015. Const RELAYS=&H57 'Relay control board I2C address '--------------------- 'GENERAL APU CONSTANTS '--------------------- Const APU=&H80 'Audio Processor Unit I2C address(BD37534FV) Const APU_INI1=&H01 'Initial setup byte #1 Const APU_INI2=&H02 'Initial setup byte #2 Const APU_INI3=&H03 'Initial setup byte #3 Const APU_SEL=&H05 'Input selector Const APU_GAIN=&H06 'Input gain Const APU_VOL=&H20 'Volume gain Const APU_LF=&H28 'Left Front fader Const APU_RF=&H29 'Right Front fader Const APU_LR=&H2A 'Left Rear fader Const APU_RR=&H2B 'Right Rear fader Const APU_SW=&H2C 'Subwoofer fader Const APU_BASS=&H41 'Bass control Const APU_MID=&H44 'Middle control Const APU_TREB=&H47 'Treble control Const APU_BG=&H51 'Bass gain Const APU_MG=&H54 'Middle gain Const APU_TG=&H57 'Treble gain Const APU_LG=&H75 'Loudness gain Const APU_RST=&HFE 'APU reset '--------------------- 'APU CONTROL CONSTANTS '--------------------- Const APU_ASM0.6=&H00 'Advanced Switch Time(MUTE) 0.6ms(00 dec) Const APU_ASM1.0=&H01 'Advanced Switch Time(MUTE) 1.0ms(01 dec) Const APU_ASM1.4=&H02 'Advanced Switch Time(MUTE) 1.4ms(02 dec) Const APU_ASM3.2=&H03 'Advanced Switch Time(MUTE) 3.2ms(03 dec) Const APU_ASI4.7=&H00 'Advanced Switch Time(INPUT) 4.7ms(00 dec) Const APU_ASI7.1=&H10 'Advanced Switch Time(INPUT) 7.1ms(16 dec) Const APU_ASI11.2=&H20 'Advanced Switch Time(INPUT) 11.2ms(32 dec) Const APU_ASI14.4=&H30 'Advanced Switch Time(INPUT) 14.4ms(48 dec) Const APU_AS0=&H00 'Advanced Switch off (00 dec) Const APU_AS1=&H80 'Advanced Switch On (128 dec) Start: Print "MUTE TIME:" Print "1-0.6, 2-1.0, 3-1.4, 4-3.2" Input A If A<1 Or A>4 Then GoTo Start Print A Select Case A Case 1 MT=APU_ASM0.6 Case 2 MT=APU_ASM1.0 Case 3 MT=APU_ASM1.4 Case 4 MT=APU_ASM3.2 End Select Print "SWITCH TIME:" Print "1-4.7, 2-7.1, 3-11.2, 4-14.4" Input B If B<1 Or B>4 Then GoTo Start Print B Select Case B Case 1 ST=APU_ASI4.7 Case 2 ST=APU_ASI7.1 Case 3 ST=APU_ASI11.2 Case 4 ST=APU_ASI14.4 End Select Print "ADVANCED SWITCH:" Print "1-ON, 2-OFF" Input C If C<1 Or C>2 Then GoTo Start Print C Select Case C Case 1 ASS=APU_AS1 Case 2 ASS=APU_AS0 End Select Print "Current byte is:"; BITE=(MT Or ST Or ASS)+4 Print Bin$(BITE,8), Str$(BITE)+" DECIMAL." End Done this way, with lots of constants, I can just easily or them together as discussed, and this seems to be working fine for building the data byte. The line that builds BITE, has "+4" on the end, as the data byte always has bit2 set for this command, and that also seems to be giving the correct results. ![]() As I am keeping all the values in constants, there is no need for a sub to compile the byte as it can be done easily in one line. I am looking into storing all this data in an array rather then pages of constant commands. The experimenting continues..... Smoke makes things work. When the smoke gets out, it stops! |
||||
JohnS Guru ![]() Joined: 18/11/2011 Location: United KingdomPosts: 4044 |
Because this thread is about MMBASIC I did not put "not used much from MMBASIC" but that is what I meant. If MMBASIC had direct I/O port access at the source code level and if people usually accessed I/O ports directly then I might (*) agree with you. But none of those things apply here... (*) actually, for PIC32 I probably wouldn't due to the CLR, SET & INV ports John |
||||
Chris Roper Senior Member ![]() Joined: 19/05/2015 Location: South AfricaPosts: 280 |
John Agreed, that is why I specifically mentioned the 8 Bit PIC's. But if anyone is going to get to grips with Bit Manipulation and logic Functions they may as well look at XOR at the same time. Non of us stay on one platform forever and knowledge is portable. Cheers Chris http://caroper.blogspot.com/ |
||||
vegipete![]() Guru ![]() Joined: 29/01/2013 Location: CanadaPosts: 1132 |
BITE=(MT Or ST Or ASS)+4 The OR function is much like adding with no carry. So BITE=MT + ST + ASS + 4 should give the result you want too, assuming there is no bit overlap between the variable. This is dangerous though, because, for example, 8 OR 8 = 8 whereas 8 + 8 = 16, a vastly different bit pattern.
So your BITE MY SORE ... should be coded as BITE=MT Or ST Or ASS Or 4 Visit Vegipete's *Mite Library for cool programs. |
||||
Grogster![]() Admin Group ![]() Joined: 31/12/2012 Location: New ZealandPosts: 9610 |
BITE=(MT Or ST Or ASS)+4 Bite my sore ass? Oh, you people..... ![]() Smoke makes things work. When the smoke gets out, it stops! |
||||
![]() |
![]() |
The Back Shed's forum code is written, and hosted, in Australia. | © JAQ Software 2025 |