Pages: 1 2 [3] 4 5 6   Go Down
Author Topic: Addressing 23017/4051 using I2C Serial Interface & PROGMEM  (Read 8882 times)
0 Members and 1 Guest are viewing this topic.
Manchester (England England)
Online Online
Brattain Member
*****
Karma: 508
Posts: 31351
Solder is electric glue
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

You are tying yourself in knots.
You have the centipede library so that removes one big problem for you, so stop worrying about the chip and how to drive it. You have that bit nailed.

What you need to do is to see how you can get from a MIDI note number to an LED number.
Supposed you used all the MIDI notes from 48 to 64 to output, that is 16 values. Then when you sent the MIDI note number all you would have to do is to do a .digitalWrite() to the MIDI note number minus 48. 

However if your MIDI note numbers are not contiguous then you have to do something else. In that case it would make sense to do it when you read the sensors because there is a contiguous relationship between LED and sensor.
Logged

New York City, NY
Offline Offline
Full Member
***
Karma: 0
Posts: 101
Arduino Rocks!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

can the pitches and LED addresses be defined at the same time ?

You send two bytes to the I2C port expander, each bit in those bytes will correspond to one of the LEDs. If you hold the current state of the lights in an int variable ( that is 16 bits ) then all you need to do is to set or clear the appropriate bit and then write it out to the port expander.
 
The MIDI will have a note number associated with the note, and the LED will have a bit number associated with its control. You have to make sure you set the right bit for the right note. There are many ways to do this, the best being a look up table. This is implemented with an array whose index represents the MIDI note and the contents represent the bit to set.
So if you are sending MIDI note 64 then you fine the bit to set in the look up array position 64.
Code:
//find it easier to use a bunch of if statements:-
[code]
if(midiNote == 64) ledBits |= 0x1;
if(midiNote == 65) ledBits |= 0x2;
if(midiNote == 66) ledBits |= 0x4;
if(midiNote == 67) ledBits |= 0x8;
if(midiNote == 68) ledBits |= 0x10;
the same goes for turning the LED off:-
Code:
if(midiNote == 64) ledBits &= ~0x1;
if(midiNote == 65) ledBits &= ~0x2;
if(midiNote == 66) ledBits &= ~0x4;
if(midiNote == 67) ledBits &= ~0x8;
if(midiNote == 68) ledBits &= ~0x10;
Note here that ~0x10 is tilda 0x10 not minus.
[/code]
« Last Edit: May 10, 2012, 11:03:43 pm by Pitchoilcan » Logged

================================
http://twit.tv/floss61
Think different
Think UbuntuStudio
============================

Manchester (England England)
Online Online
Brattain Member
*****
Karma: 508
Posts: 31351
Solder is electric glue
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I don't know why you are just posting lumps of the data sheet for the MCP23X17 chip. I can read the original and so can you.

Forget the data sheet about the chip. It is way too complicated for you to understand. The Centipede library offers you easy access to the hardware.
 
Let me try again to tell you about this.
There are TWO ways of turning the lights on, you only need to use one of them:-
1) Work out the number to use with a .digitalRead()
2) Set and clear bits in an int variable and use .portWrite()

Method 1 is easier to do when you are actually sending the MIDI data.
Method 2 is easier to do when you are reading the sensors in.
Logged

New York City, NY
Offline Offline
Full Member
***
Karma: 0
Posts: 101
Arduino Rocks!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

pondering 48*2  'if' statements
TWO ways of turning the lights on, you only need to use one of them:-

2) Set and clear bits in an int variable and use .portWrite() //Write XOR 230x17 Expander Pins

So if you are sending MIDI note 64 then you fine the bit to set in the look up array position 64.
 //I find it easier to use a bunch of if statements:-
Code:
if(midiNote == 64) ledBits |= 0x1;
if(midiNote == 65) ledBits |= 0x2;
if(midiNote == 66) ledBits |= 0x4;
if(midiNote == 67) ledBits |= 0x8;
if(midiNote == 68) ledBits |= 0x10;
the same goes for turning the LED off:-
Code:
if(midiNote == 64) ledBits &= ~0x1;
if(midiNote == 65) ledBits &= ~0x2;
if(midiNote == 66) ledBits &= ~0x4;
if(midiNote == 67) ledBits &= ~0x8;
if(midiNote == 68) ledBits &= ~0x10;
There is no difference between an LED and a solenoid.  I did not know that.
Good to know  smiley-draw
I now understand it it's matter of both  Bitwise AND as well as Bitwise XOR.
« Last Edit: May 10, 2012, 08:21:28 pm by Pitchoilcan » Logged

================================
http://twit.tv/floss61
Think different
Think UbuntuStudio
============================

Manchester (England England)
Online Online
Brattain Member
*****
Karma: 508
Posts: 31351
Solder is electric glue
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
There is no difference between an LED and a solenoid.
Now if you are going to be silly and take things out of context like that I won't play with you any more.
That statement was made in the context of you saying that the code only turned on solenoids and not LEDs. In the context of the code needed to turn a device on the is indeed no difference between an LED and a solenoid.

Quote
pondering 48*2  'if' statements
Well that is just silly, you don't need 96 if statements to control just 16 LEDs do you?

Logged

New York City, NY
Offline Offline
Full Member
***
Karma: 0
Posts: 101
Arduino Rocks!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

]Alternative conversion process | Just a reminder]
Quote
A shortcut to manually convert a binary number into its two's complement is to start at the least significant bit (LSB), and copy all the zeros (working from LSB toward the most significant bit) until the first 1 is reached; then copy that 1, and flip all the remaining bits. This shortcut allows a person to convert a number to its two's complement without first forming its ones' complement. For example: the two's complement of "0011 1100" is "1100 0100", where the underlined digits were unchanged by the copying operation (while the rest of the digits were flipped).
In computer circuitry, this method is no faster than the "complement and add one" method; both methods require working sequentially from right to left, propagating logic changes. The method of complementing and adding one can be sped up by a standard carry look-ahead adder circuit; the alternative method can be sped up by a similar logic transformation.
source: http://en.wikipedia.org/wiki/Two%27s_complement
I said 48 because I have 48 inputs. at the moment only 24 piezos and 16 LEDs but I hope go to 48 piezos and perhaps buy a centipede shield and use 48 LED although at the moment twelve or 16 LED would be enough. Just extrapolating for the entire mux-shield;
Lol about the solenoid! smiley-yell

guess I'm NOT 'doing the steps'
Quote
You have the centipede library so that removes one big problem for you, so stop worrying about the chip and how to drive it. You have that bit nailed.
« Last Edit: May 10, 2012, 11:12:31 pm by Pitchoilcan » Logged

================================
http://twit.tv/floss61
Think different
Think UbuntuStudio
============================

New York City, NY
Offline Offline
Full Member
***
Karma: 0
Posts: 101
Arduino Rocks!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
CS.portMode(0, 0b0111111001111110); // 0 = output, 1 = input
CS.portWrite(0, 0b1000000110000001); // 0 = LOW, 1 = HIGH
marco_c writing it out on paper really helps. so I'm doing the steps..Thanks mate!
Back to the data sheet for a moment and doing the steps
is this any good for first 12 LEDs?, there maybe errors here.
pondering.........
table 6 (IOCON=0)
Address
(hex)
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15
table 5 (IOCON=1)
Address
(hex)

00 01 02 03 04 05 06 07 08 09 0A 10 11 12 13 14 15 16 17 18 19 1A

 |     |    |    |     |    |    |    |     |    |    |    |     |    |    |     |    |     |    |    |    |  
 __C  C# D  D# E  F   F# G  G# A  A#  B  C OFF________________

     60 61 62 63 64 65 66 67 68 69 70 71 72   Note numbers
============================================================================
Table 1-5
  (iocon=1)    |     Table 1-6 (iocon=0)
             A    |    B
ALL OFF     00 10 | 00 01  C4
C#        01 11 | 02 03  D
D#        02 10 | 04 05  E
F        03 13 | 06 07  F#
G        04 14 | 08 09  G#
A             05 15 | 0A 0B  A#
B        06 16 | 0C OD    C5
NULL     07 17 | 0E OF  NULL or OFF
NULL     08 18 | 10 11  NULL
NULL     09 19 | 12 13  NULL
NULL     A0 1A | 14 16  NUL                      
=====================
Table #
a  00 01 02 03 04 05 06 07 08 09 0A   //bank A
b  10 11 12 13 14 15 16 17 18 19 1A   //bank B

a 00 02 04 06 08 0A 0C 0E 10 12 14    //bank A
b 01 03 05 07 09 0B 0D 0F 11 13 15   //bank B
Table #
Quote
1.3.1
BYTE MODE AND SEQUENTIAL
MODE
The MCP23X17 family has the ability to operate in Byte
mode or Sequential mode (IOCON.SEQOP).
Byte Mode..............

A special mode (Byte mode with IOCON.BANK = 0)
causes the address pointer to toggle between
associated A/B register pairs. For example, if the BANK
bit is cleared and the Address Pointer is initially set to
address 12h (GPIOA) or 13h (GPIOB), the pointer will
toggle between GPIOA and GPIOB. Note that the
Address Pointer can initially point to either address in
the register pair.
Sequential mode...............
 
These two modes are not to be confused with single
writes/reads and continuous writes/reads that are
serial protocol sequences.

*CS.portMode(0, 0b0111111001111110); // 0 = output, 1 = input
*CS.portWrite(0, 0b1000000110000001); // 0 = LOW, 1 = HIGH

I also find this very helpful:
=====

Quote
A left arithmetic shift of a binary number by 1. The empty position in the least significant bit is filled with a zero. Note that arithmetic left shift may cause an overflow; this is the only way it differs from logical left shift.

Quote
A right arithmetic shift of a binary number by 1. The empty position in the most significant bit is filled with a copy of the original MSB.

Source: http://en.wikipedia.org/wiki/Arithmetic_shift

« Last Edit: May 12, 2012, 12:02:35 am by Pitchoilcan » Logged

================================
http://twit.tv/floss61
Think different
Think UbuntuStudio
============================

Sydney, Australia
Offline Offline
Edison Member
*
Karma: 27
Posts: 1178
Big things come in large packages
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

If you are using the Centipede library then your mapping should be easier.

As Grumpy_Mike says, you can pretty much forget that you have the hardware there and just turn on the output you need using the correct functions in the CS library, so you really need to read the library documentation and code examples.

As I don't have experience with the libraries I'll watch from the sidelines and learn (He's probably in a better time zone anyway).
Logged

Arduino libraries http://arduinocode.codeplex.com
Parola hardware & library http://parola.codeplex.com

New York City, NY
Offline Offline
Full Member
***
Karma: 0
Posts: 101
Arduino Rocks!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Not a bad tutorial- [using just the wire library]    [ Two's complement ] the 23017 data sheet again http://ww1.microchip.com/downloads/en/DeviceDoc/21952b.pdf
tronixstuff 230x1 tutorial revisited:
http://tronixstuff.wordpress.com/2011/08/26/tutorial-maximising-your-arduinos-io-ports/
Now to examine how to use the IC in our sketches. As you should know by now most I2C devices have several registers that can be addressed. Each address holds one byte of data that determines various options. With the MCP23017 the registers can be ordered in one of two ways – see tables 1.3 and 1.4   on page nine of the data sheet. In our examples we will use the addresses listed on table 1.4. So the first command to use in void setup() is:
Code:
 Wire.beginTransmission(0x20);
  Wire.send(0x12);
  Wire.send(0x20); // use table 1.4 addressing
  Wire.endTransmission();
The next is to set the I/O ports as inputs or outputs. First we will work with outputs. When the MCP23017 is turned on or reset, it defaults to inputs so we need to change them. So we use:
Code:
 Wire.beginTransmission(0x20);
  Wire.send(0x00); // IODIRA register
  Wire.send(0x00); // set all of bank A to outputs
  Wire.send(0x00); // set all of bank B to outputs
  Wire.endTransmission();
Go back to the data sheet and see table 1.4. Notice how we started with the IODIRA (“I/O direction, bank A”) register at 0×00 and sent two bytes? You can do this without having to separate address the second register. This only works when the registers have sequential addresses, as in this example we wanted a byte to go to 0×00 then 0×01. We sent zero which in binary is 00000000 – each bit refers to one output of the bank and refers to I/O pins 7~0.
So now we are in void loop()  or a function of your own creation and want to control some output pins. To control bank A, we use:
Code:
 Wire.beginTransmission(0x20);
  Wire.send(0x12); // address bank A
  Wire.send(??);  // value to send
  Wire.endTransmission();
replacing ?? with the binary or equivalent hexadecimal or decimal value to send to the register. To calculate the required number, consider each I/O pin from 7 to 0 matches one bit of a binary number – 1 for on, 0 for off. So you can insert a binary number representing the output levels. Or if binary does your head in, convert it to hexadecimal. So for example, you want pins 7 and 1 on. In binary that would be 10000010, in hexadecimal that is 0×82, or 130 decimal. (Using decimals is convenient if you want to display values from an incrementing value or function result).

If you had some LEDs via resistors connected to the outputs, you would have this as a result of sending 0×82:

Now if you want to address all the outputs at once, just send the byte for bank B after bank A. For example, we want bank A to be 11001100 and bank B to be 10001000 – so we send the following:

  
Code:
Wire.beginTransmission(0x20);
  Wire.send(0xCC); // address bank A
  Wire.send(0x88); // address bank B
  Wire.endTransmission();
… with the results as such (bank B on the left, bank A on the right):

You can also just address bank B, if so bank A does not change. Now let’s put all of this output knowledge into a more detailed example. From a hardware perspective we are using a circuit as described above, with the addition of a 560 ohm resistor followed by an LED thence to ground from on each of the sixteen outputs. Here is the sketch (download):

Example 41.1
Code:
/*
 Example 41.1 - Microchip MCP23017 with Arduino
 http://tronixstuff.wordpress.com/tutorials > chapter 41
 John Boxall | CC by-sa-nc
*/

// pins 15~17 to GND, I2C bus address is 0x20

#include "Wire.h"

void setup()
{
  Wire.begin(); // wake up I2C bus

  // setup addressing style
  Wire.beginTransmission(0x20);
  Wire.send(0x12);
  Wire.send(0x20); // use table 1.4 addressing
  Wire.endTransmission();

  // set I/O pins to outputs
  Wire.beginTransmission(0x20);
  Wire.send(0x00); // IODIRA register
  Wire.send(0x00); // set all of bank A to outputs
  Wire.send(0x00); // set all of bank B to outputs
  Wire.endTransmission();
}

void binaryCount()
{
  for (byte a=0; a<256; a++)
  {
    Wire.beginTransmission(0x20);
    Wire.send(0x12); // GPIOA
    Wire.send(a);    // bank A
    Wire.send(a);    // bank B
    Wire.endTransmission();
    delay(100);
  }
}

void loop()
{
  binaryCount();
  delay(500);
}
And here is the example blinking away:

Although that may have seemed like a simple demonstration, it was created show how the outputs can be used. So now you know how to control the I/O pins set as outputs. Note that you can’t source more than 25 mA of current from each pin, so if switching higher current loads use a transistor and an external power supply and so on.

Now let’s turn the tables and work on using the I/O pins as digital inputs. The MCP23017 I/O pins default to input mode, so all we need to do is set the addressing method as such in void setup()
Code:
// setup addressing style
  Wire.beginTransmission(0x20);
  Wire.send(0x12);
  Wire.send(0x20); // use table 1.4 addressing
  Wire.endTransmission();
« Last Edit: May 20, 2012, 09:20:36 am by Pitchoilcan » Logged

================================
http://twit.tv/floss61
Think different
Think UbuntuStudio
============================

New York City, NY
Offline Offline
Full Member
***
Karma: 0
Posts: 101
Arduino Rocks!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

To Hex, or not to hex?.... [table A or table B][c or d]
An alternative conversion process
Quote
A shortcut to manually convert a binary number into its two's complement is to start at the least significant bit (LSB), and copy all the zeros (working from LSB toward the most significant bit) until the first 1 is reached; then copy that 1, and flip all the remaining bits. This shortcut allows a person to convert a number to its two's complement without first forming its ones' complement. For example: the two's complement of "0011 1100" is "1100 0100", where the underlined digits were unchanged by the copying operation (while the rest of the digits were flipped).
In computer circuitry, this method is no faster than the "complement and add one" method; both methods require working sequentially from right to left, propagating logic changes. The method of complementing and adding one can be sped up by a standard carry look-ahead adder circuit; the alternative method can be sped up by a similar logic transformation.
source: http://en.wikipedia.org/wiki/Two%27s_complement
  defining the LED and Note bits like so:
Code:
if(midiNote == 64) ledBits |= 0x1;
if(midiNote == 65) ledBits |= 0x2;
if(midiNote == 66) ledBits |= 0x4;
if(midiNote == 67) ledBits |= 0x8;
if(midiNote == 68) ledBits |= 0x10;
the same goes for turning the LED off:-
Code:
if(midiNote == 64) ledBits &= ~0x1;
if(midiNote == 65) ledBits &= ~0x2;
if(midiNote == 66) ledBits &= ~0x4;
if(midiNote == 67) ledBits &= ~0x8;
if(midiNote == 68) ledBits &= ~0x10;
« Last Edit: May 11, 2012, 11:54:26 pm by Pitchoilcan » Logged

================================
http://twit.tv/floss61
Think different
Think UbuntuStudio
============================

Sydney, Australia
Offline Offline
Edison Member
*
Karma: 27
Posts: 1178
Big things come in large packages
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Pointers and integers are two different things which is why you are stopped form doing that. It has no meaning, like comparing the address of a house to the house itself.

What are you trying to do?
Logged

Arduino libraries http://arduinocode.codeplex.com
Parola hardware & library http://parola.codeplex.com

New York City, NY
Offline Offline
Full Member
***
Karma: 0
Posts: 101
Arduino Rocks!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

//Table 1-2  (0)
if(PadNote == 60) ledBits |= 0x01;
if(PadNote == 61) ledBits |= 0x02;
if(PadNote == 62) ledBits |= 0x03;
if(PadNote == 63) ledBits |= 0x04;
if(PadNote == 64) ledBits |= 0x05;

               // the same goes for turning the LED off:-

if(PadNote == 60) ledBits &= ~0x01;
if(PadNote == 61) ledBits &= ~0x02;
if(PadNote == 62) ledBits &= ~0x03;
if(PadNote == 63) ledBits &= ~0x04;
if(PadNote == 64) ledBits &= ~0x05;
Quote
In mathematics and computer science, hexadecimal (also base 16, or hex) is a positional numeral system with a radix, or base, of 16. It uses sixteen distinct symbols, most often the symbols 0–9 to represent values zero to nine, and A, B, C, D, E, F (or alternatively a–f) to represent values ten to fifteen. For example, the hexadecimal number 2AF3 is equal, in decimal, to (2 × 163) + (10 × 162) + (15 × 161) + (3 × 160), or 10,995.
Each hexadecimal digit represents four binary digits (bits), and the primary use of hexadecimal notation is a human-friendly representation of binary-coded values in computing and digital electronics. One hexadecimal digit represents a nibble, which is half of an octet (8 bits). For example, byte values can range from 0 to 255 (decimal), but may be more conveniently represented as two hexadecimal digits in the range 00 to FF. Hexadecimal is also commonly used to represent computer memory addresses.
OK back to my scrapbook
Quote
16 (hexadecimal)      0x7B    leading "0x"     characters 0-9, A-F, a-f valid  
« Last Edit: May 20, 2012, 09:19:33 am by Pitchoilcan » Logged

================================
http://twit.tv/floss61
Think different
Think UbuntuStudio
============================

Sydney, Australia
Offline Offline
Edison Member
*
Karma: 27
Posts: 1178
Big things come in large packages
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

padNote is an array of characters (or bytes, probably)
Code:
unsigned char PadNote[48] = {35,36,37,38,39,40,41,42,

to access one of the values of padNote you need to reference it using an array index, shown as i in the code below

Code:
if (padNote[i] == 99) ledPin |=  0x1;

Just using padNote on it's own, in C++, tells the compiler you are using the address of the array. That is an advanced topic for you to learn later.
« Last Edit: May 12, 2012, 02:30:12 am by marco_c » Logged

Arduino libraries http://arduinocode.codeplex.com
Parola hardware & library http://parola.codeplex.com

New York City, NY
Offline Offline
Full Member
***
Karma: 0
Posts: 101
Arduino Rocks!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

void readSensors(int analogPin){
    //This for loop is used to scroll through and store the 16 inputs on the FIRST multiplexer
  for (int i=0; i<16; i++){
    digitalWrite(CONTROL0, (i&15)>>3);
    digitalWrite(CONTROL1, (i&7)>>2);  
    digitalWrite(CONTROL2, (i&3)>>1);  
    digitalWrite(CONTROL3, (i&1));    

    //Read and store the input value at a location in the array
    if(analogPin==0){
      mux0array = analogRead(analogPin);
    }
    else if(analogPin==1){
      mux1array = analogRead(analogPin);
    }
    else if(analogPin==2){
      mux2array = analogRead(analogPin);
    }
    //Table 1-2  (0)
if(PadNote == 60) ledBits |= 0x01;
if(PadNote == 61) ledBits |= 0x02;
if(PadNote == 62) ledBits |= 0x03;
if(PadNote == 63) ledBits |= 0x04;
if(PadNote == 64) ledBits |= 0x05;

if(PadNote == 65) ledBits |= 0x06;
if(PadNote == 66) ledBits |= 0x07;
if(PadNote == 67) ledBits |= 0x08;
if(PadNote == 68) ledBits |= 0x09;
if(PadNote == 69) ledBits |= 0x0A;

if(PadNote == 70) ledBits |= 0x0B;
if(PadNote == 71) ledBits |= 0x0C;
////if(PadNote == 72) ledBits |= 0x0D;
////if(PadNote == 73) ledBits |= 0x0E;
////if(PadNote == 74) ledBits |= 0x0F;

               // the same goes for turning the LED off:-

if(PadNote == 60) ledBits &= ~0x01;
if(PadNote == 61) ledBits &= ~0x02;
if(PadNote == 62) ledBits &= ~0x03;
if(PadNote == 63) ledBits &= ~0x04;
if(PadNote == 64) ledBits &= ~0x05;

if(PadNote == 65) ledBits &= ~0x06;
if(PadNote == 66) ledBits &= ~0x07;
if(PadNote == 67) ledBits &= ~0x08;
if(PadNote == 68) ledBits &= ~0x09;
if(PadNote == 69) ledBits &= ~0x0A;

if(PadNote == 70) ledBits &= ~0x0B;
if(PadNote == 71) ledBits &= ~0x0C;
////if(PadNote == 72) ledBits &= ~0x0D;
////if(PadNote == 73) ledBits &= ~0x0E;
////if(PadNote == 74) ledBits &= ~0x0F;
  }
}
Logged

================================
http://twit.tv/floss61
Think different
Think UbuntuStudio
============================

New York City, NY
Offline Offline
Full Member
***
Karma: 0
Posts: 101
Arduino Rocks!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

added
Code:
#include <Centipede.h>
#include <Wire.h>

Centipede ledBits; // create  object

  ledBits.initialize(); // set all registers to default
 
  ledBits.portMode(0, 0b0000000000000000); // set all pins on chip 0 to output
Not I get
twelve of these :
Quote
no match for 'operator |=' in 'ledBits |=1'  
and
twelve of these :
Quote
no match for 'operator &=' in 'ledBits &= -0x0000000002'  
How do I resolve this ?
« Last Edit: May 12, 2012, 03:38:58 pm by Pitchoilcan » Logged

================================
http://twit.tv/floss61
Think different
Think UbuntuStudio
============================

Pages: 1 2 [3] 4 5 6   Go Up
Jump to: