Spi communicatie met een mcp4251 (potmeter)

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • huub8
  • Registratie: Maart 2009
  • Laatst online: 28-06-2021
Ik probeer al een paar uur een digitale potmeter (de mcp4251 dual channel 10K) aan te sturen.
Voor zover ik het begrijp uit de datasheet (pagina 47) kan dit door 8 en 16 bit commando's, met de 16 bit zou je gewoon de waarde moeten kunnen doorgeven. Maar bij mij werkt het niet, ik communiceer met een microcontroller (een 18f4520) werkend op 20mhz (maar de SPI werkt op een lagere frequentie).

Ik heb ook een led aangesloten, die knipper netjes om de seconde (tussen de momenten dat de data word verzonden) dus de code loopt wel. De mcp4251 geeft echter altijd een voltage van 1,814 op beide wipers (De A pinnen zijn op 5 volt aangesloten, de B op de GND). De microcontroller is aangesloten op de mcp4251 zoals in de code aangegeven, alleen weet ik niet wat ik met de SHDN pin moet, als ik die op de GND aansluit geeft hij op beide pinnen wipers 0V, anders die 1,814V.

De code is geschreven in mikroc, het is de bedoeling dat de onderstaande code de eerste wiper halverwege insteld (totale bereik is 257). De code is gebaseerd op het voorbeeld van mikroc voor de spi module.

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// spi module connections
sbit Chip_Select at RC0_bit;
sbit SoftSpi_CLK at RC3_bit;
sbit SoftSpi_SDI at RC4_bit;
sbit SoftSpi_SDO at RC5_bit;

sbit Chip_Select_Direction at TRISC0_bit;
sbit SoftSpi_CLK_Direction at TRISC3_bit;
sbit SoftSpi_SDI_Direction at TRISC4_bit;
sbit SoftSpi_SDO_Direction at TRISC5_bit;
// End spi module connections

unsigned int value;

void InitMain() {
  TRISB = 0b00000000;                    // all pins on PORTB are Output pins
  TRISC = 0b00000000;                    // all pins on PORTC are Output pins
  CMCON = 7;                             // all pins digital
  Chip_Select = 1;                       // Deselect
  Chip_Select_Direction = 0;             // Set CS# pin as Output
  Soft_SPI_Init();                       // Initialize Soft_SPI
}


void Output() {
  Chip_Select = 0;                       // Select chip
  delay_us(5);
  Soft_SPI_Write(0x00);                  // Send high byte via Soft SPI
  Soft_SPI_Write(0x80);                  // Send low byte via Soft SPI
  delay_us(5);
  Chip_Select = 1;                       // Deselect chip
  delay_us(5);
}

void main() {

    InitMain();                            // Perform main initialization

    while (1) {                            // Endless loop
      Output();                   // Send value to chip
      Delay_ms(1000);                         // Slow down key repeat pace
      PORTB = ~PORTB;                         // to check if the code is running
    }
}


Het commando dat word verstuurd is dus:
0000 0000
1000 0000

wat naar mijn idee zou moeten werken, dit is namelijk hoe volgens een ander forum de commando's moeten worden opgebouwd:

Basically you are going to be sending bytes down the SPI bus t your chip. You can send either 8 bit commands or 16 bit commands. In either case the 4 most significant bits of the command are an address. The table on page 48 of the datsheet lets you know that an address 0x00 (hex 0) is wiper 0, and 0x01 is wiper 1. The next 2 bits determine the command, and if required the next 10 bits are data. Does that make sense?

Acties:
  • 0 Henk 'm!

  • AlexanderB
  • Registratie: Maart 2007
  • Laatst online: 09-05 19:05

AlexanderB

7800 rpm

welke SPI frequentie stuurt je micro uit? van mijn experimentjes met digi-pots weet ik nog dat dat n hele lage moet zijn, iig lager dan de SPI frequentie die ik normaal gebruikte voor mn programmer (om maar wat te noemen)

alles correct aangesloten (always ask the obvious)

little endian versus big endian geen probleem?

Acties:
  • 0 Henk 'm!

  • huub8
  • Registratie: Maart 2009
  • Laatst online: 28-06-2021
Op de website van mikroc is dit te lezen:

Library configuration:
SPI to Master mode
Clock value = 20 kHz.
Data sampled at the middle of interval.
Clock idle state low.
Data sampled at the middle of interval.
Data transmitted at low to high edge.

Ik kan daar niets over de gebruikte endian vinden.

Acties:
  • 0 Henk 'm!

  • AlexanderB
  • Registratie: Maart 2007
  • Laatst online: 09-05 19:05

AlexanderB

7800 rpm

oh.. endian is zegmaar... 0x80 kan je schijven als 1000 0000... (dat is little endian, kleinste getal laatst) of 0000 0001 (big endian, grootste getal laatst) en als je avr dat verkeerdom doet, dan werkt het uiteraard niet..

(tja, het zal maar niet werken om zo iets stompzinnigs)

mijn conclusie is in ieder geval dat de chip of helemaal geen datasignaal ontvangt, of niet ontvangt wat ie wil horen, omdat ie gewoon in zn startup-positie blijft staan..

bij de chip die ik gebruik had was t wat makkelijker, omdat die gewoon op een 8 bit signaal reageerde, zonder adressering (adressering via CS)

[edit:] en clock value moet <10khz volgens de datasheet, dus doe dat eerst..

[ Voor 6% gewijzigd door AlexanderB op 26-04-2012 21:29 ]


Acties:
  • 0 Henk 'm!

  • huub8
  • Registratie: Maart 2009
  • Laatst online: 28-06-2021
Ik ben maar overgestapt op de hardware spi library, aangezien ik nergens een instelling kon vinden voor de snelheid in de software library, litle endian of big endian maakt lijkt mijn niet uit, behalve dan dat de waardes van de weerstand van de potmeter ervan afhangen, maar hij zou wel gewoon een waarde moeten aannemen, (de command bestaat immers uit alleen maar nullen, dus daarbij maakt het niet uit, dus hij zou zoiezo iets moeten instellen).

De code is nu als volgt:

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// chip module connections
sbit Chip_Select1 at RC0_bit;                                                                                                                                                                        sbit Chip_Select at RC0_bit;
sbit Chip_Select_Direction at TRISC0_bit;
// End chip module connections

unsigned int value;

void InitMain() {
  Chip_Select1 = 1;                       // Deselect
  Chip_Select_Direction = 0;             // Set CS# pin as Output
  // Set SPI1 module to master mode, clock = Fosc/64, data sampled at the middle of interval, clock idle state low and data transmitted at low to high edge:
SPI1_Init_Advanced(_SPI_MASTER_OSC_DIV64, _SPI_DATA_SAMPLE_MIDDLE, _SPI_CLK_IDLE_LOW, _SPI_LOW_2_HIGH);
}

void Output() {
  Chip_Select1 = 0;                       // Select chip

  // Send High Byte
  SPI1_Write(0b00000000);                      // Send high byte via SPI

  // Send Low Byte
  SPI1_Write(0b10000000);                      // Send low byte via SPI

  Chip_Select1 = 1;                       // Deselect chip
}

void main() {
  CMCON = 7;
  InitMain();                            // Perform main initialization

 while (1) {                             // Endless loop
    Output();                   // Send value to chip
    Delay_ms(1000);                         // Slow down key repeat pace
  }
}

Acties:
  • 0 Henk 'm!

  • Stoney3K
  • Registratie: September 2001
  • Laatst online: 11-10 01:22

Stoney3K

Flatsehats!

Misschien dat er een slordige timing zit tussen CS en het versturen van data over je SPI bus?

MAW: Als je CS laag maakt en direct data begint te sturen, misschien dat de chip een langere set-up tijd en hold time voor CS verwacht. Waardoor je dus de eerste paar bits aan data misloopt.

Aan het einde van je verzending hetzelfde: Misschien dat de CS 'te vroeg' weer hoog wordt en de chip weer uitschakelt. Een delay van 1ms vóór en na je SPI verzendinstructie kan nog wel eens verschil maken.

Zet het daar maar neer! -- It's time to party like it's 1984 -- Soundcloud


Acties:
  • 0 Henk 'm!

  • huub8
  • Registratie: Maart 2009
  • Laatst online: 28-06-2021
Ik heb wat delays toegevoegd, maar hij reageerd nog steeds niet:

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
// chip module connections
sbit Chip_Select1 at RC0_bit;
sbit Chip_Select_Direction at TRISC0_bit;
// End chip module connections

void InitMain() {
TRISB = 0;
TRISC = 0;
PORTB = 0;
PORTC = 0;
  Chip_Select1 = 1;                       // Deselect
  Chip_Select_Direction = 0;             // Set CS# pin as Output
  // Set SPI1 module to master mode, clock = Fosc/64, data sampled at the middle of interval, clock idle state low and data transmitted at low to high edge:
SPI1_Init_Advanced(_SPI_MASTER_OSC_DIV64, _SPI_DATA_SAMPLE_MIDDLE, _SPI_CLK_IDLE_LOW, _SPI_LOW_2_HIGH);
}

void Output() {
  delay_ms(1);
  Chip_Select1 = 0;                       // Select chip
  delay_ms(1);
  
  // Send High Byte
  SPI1_Write(0b00000000);                      // Send high byte via SPI

  // Send Low Byte
  SPI1_Write(0b11111111);                      // Send low byte via SPI

  delay_ms(1);
  Chip_Select1 = 1;                       // Deselect chip
  delay_ms(1);
}

void main() {
  delay_ms(2000);
  CMCON = 7;
  InitMain();                            // Perform main initialization

 while (1) {
  Output();                   // Send value to chip
  Delay_ms(100);                         // Slow down key repeat pace
 }
}


EDIT:
Ik heb even snel een schema gemaakt (deels in paint, eagle kende niet alle onderdelen), misschien dat ik iets verkeerd heb aangesloten?

[ Voor 6% gewijzigd door huub8 op 27-04-2012 20:08 ]


Acties:
  • 0 Henk 'm!

  • huub8
  • Registratie: Maart 2009
  • Laatst online: 28-06-2021
Ik ben er denk ik al achter wat er fout gaat, volgens mij zit het hem in het sturen van een waarde als 0b0000000
Als ik namerlijk een char variabele stuur met waarde 0 dat gaat hij wel gewoon netjes uit (zoiets word ook in de voorbeeldcode gedaan van mikroc). Maar nog niet alles werkt, zo volgt hij hoogstens twee commando's op en negeert dan alles, deze code zorgt ervoor dat hij eer op bijna 0V gaat, en dan rond de 0.3V, maar daarna stopt hij ermee:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
// chip module connections
sbit Chip_Select1 at RC0_bit;
sbit Chip_Select_Direction at TRISC0_bit;
// End chip module connections

int x;

void InitMain() {
TRISB = 0;
TRISC = 0;
PORTB = 0;
PORTC = 0;
  Chip_Select1 = 1;                       // Deselect
  Chip_Select_Direction = 0;             // Set CS# pin as Output
  // Set SPI1 module to master mode, clock = Fosc/64, data sampled at the middle of interval, clock idle state low and data transmitted at low to high edge:
SPI1_Init_Advanced(_SPI_MASTER_OSC_DIV16, _SPI_DATA_SAMPLE_MIDDLE, _SPI_CLK_IDLE_LOW, _SPI_LOW_2_HIGH);
}

void Output(char value1, char value2) {
  Chip_Select1 = 0;                       // Select chip
  delay_ms(1);
  
  // Send High Byte
  SPI1_Write(value1);             // Send high byte via SPI

  
    // Send low Byte
  SPI1_Write(value2);                      // Send high byte via SPI


  delay_ms(1);
  Chip_Select1 = 1;                       // Deselect chip
}

void main() {
  delay_ms(1000);
  CMCON = 7;
  InitMain();                            // Perform main initialization
  delay_ms(1000);

         Output(0,10);
         delay_ms(5000);
         PORTB = ~PORTB;

         Output(0,20);
         delay_ms(5000);
         PORTB = ~PORTB;
         
         Output(0,40);
         delay_ms(5000);
         PORTB = ~PORTB;
         
         Output(0,60);
         delay_ms(5000);
         PORTB = ~PORTB;
         
         Output(0,80);
         delay_ms(5000);
         PORTB = ~PORTB;
         
         Output(0,100);
         delay_ms(5000);
         PORTB = ~PORTB;
         
         Output(0,120);
         delay_ms(5000);
}


Ik heb dus het idee dat het geheel wel juist is aangesloten, maar dat mijn commando's niet goed overkomen.

Acties:
  • 0 Henk 'm!

  • 3xhaas
  • Registratie: Februari 2002
  • Laatst online: 26-09-2024
Huub schreef:
De microcontroller is aangesloten op de mcp4251 zoals in de code aangegeven, alleen weet ik niet wat ik met de SHDN pin moet, als ik die op de GND aansluit geeft hij op beide pinnen wipers 0V, anders die 1,814V.
Datasheet 5.3 pagina 39
The SHDN pin is available on the dual potentiometer
devices. When the SHDN pin is forced active (VIL):
• The P0A and P1A terminals are disconnected
• The P0W and P1W terminals are simultaneously
connect to the P0B and P1B terminals, respectively
(see Figure 5-2)
• The Serial Interface is NOT disabled, and all
Serial Interface activity is executed
The Hardware Shutdown pin mode does NOT corrupt
the values in the Volatile Wiper Registers nor the
TCON register. When the Shutdown mode is exited
(SHDN pin is inactive (VIH)):
• The device returns to the Wiper setting specified
by the Volatile Wiper value
• The TCON register bits return to controlling the
terminal connection state
Dus je SHDN-pin/functie werkt in ieder geval goed ;)
[b]Datasheet 6.2 pag 44[/b[
6.2 The SPI Modes
The SPI module supports two (of the four) standard SPI
modes. These are Mode 0,0 and 1,1. The mode is
determined by the state of the SDI pin on the rising
edge of the 1st clock bit (of the 8-bit byte).
6.2.1 MODE 0,0
In Mode 0,0: SCK idle state = low (VIL), data is clocked
in on the SDI pin on the rising edge of SCK and clocked
out on the SDO pin on the falling edge of SCK.
6.2.2 MODE 1,1
In Mode 1,1: SCK idle state = high (VIH), data is
clocked in on the SDI pin on the rising edge of SCK and
clocked out on the SDO pin on the falling edge of SCK
Er worden dus twee types SPI ondersteund. Ik zou anders zelf even het SPI-protocol schrijven en het zorgen dat de clock etc allemaal goed lopen. Dan weet je in ieder geval zeker dat je de code goed uitstuurt.
Ik ga er van het gemak vanuit dat je eerste software SPI iets standaards van de compiler was aangezien ik er geen code van terug vind.

Acties:
  • 0 Henk 'm!

  • huub8
  • Registratie: Maart 2009
  • Laatst online: 28-06-2021
Zelf een software spi maken lijkt mij wat te ingewikkeld, de eerste spi versie was de software spi library van mikroc, de tweede de hardware spi library van mikroc. De enige plek waar je daar zaken kunt instellen is bij de initialisatie, daar is het volgende bij in te stellen:

void SPI1_Init_Advanced(unsigned short master_slav, unsigned short data_sample, unsigned short clock_idle, unsigned short transmit_edge);

De mogelijke waardes zijn hier te vinden, ik dacht dat het al goed ingesteld was, maar ik kan het best fout hebben.

Het voorbeeld waar mijn code sterk op is gebaseerd is daar ook te vinden.

Acties:
  • 0 Henk 'm!

  • 3xhaas
  • Registratie: Februari 2002
  • Laatst online: 26-09-2024
zelf SPI code schrijven is niet zo lastig hoor
Ik ben een beetje roestig ermee, maar iets als onderstaand moet toch voldoende zijn om het mee te testen. (Alleen voor instellen v/d potmeter)
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void Eigen_SPI_Write(unsigned char value1, unsigned char value2){
  output_low(pin_C3); //SCK low
  output_low(pin_C0); //CS low
  delay_ms(1);

  for(i=0;i<8;++i){
    output_bit(PIN_C5,shift_right(&value1,1,0)); //MCU:SDO>POT:SDI
    output_high(pin_C3); //SCK low
    output_low(pin_C3);  //SCK low
    }
  for(i=0;i<8;++i){
    output_bit(PIN_C5,shift_right(&value2,1,0)); //MCU:SDO>POT:SDI
    output_high(pin_C3); //SCK low
    output_low(pin_C3);  //SCK low
    }
  output_high(pin_C0); //CS high
}

Ook zou ik twee verschillende waarden naar elke potmeter sturen, bv naar de ene 0xF0 en de andere 0x0F.

Zit ik net goed naar je schema te kijken zie ik dat je SDI naar SDI en SDO naar SDO hebt gedaan. Dat is niet goed. De SDO van je MCU moet naar de SDI van je potmeter en vice versa.
SDI = serial data input
SDO = serial data output
SCK = sercial clock

Als je die omdraait zal het waarschijnlijk ook wel werken.

Acties:
  • 0 Henk 'm!

  • AlexanderB
  • Registratie: Maart 2007
  • Laatst online: 09-05 19:05

AlexanderB

7800 rpm

euh.. en de SDO van de potmeter moet naar de volgende device in de ketting, en als die dr niet is, gewoon lekker laten hangen.. / terminaten met n weerstandje als je dat nuttig vind

Acties:
  • 0 Henk 'm!

  • 3xhaas
  • Registratie: Februari 2002
  • Laatst online: 26-09-2024
AlexanderB schreef op zaterdag 28 april 2012 @ 00:17:
euh.. en de SDO van de potmeter moet naar de volgende device in de ketting, en als die dr niet is, gewoon lekker laten hangen.. / terminaten met n weerstandje als je dat nuttig vind
Bij dit device staat er toch in de datasheet dat je SDI>SDO en vice versa moet aansluiten(pag. 41) en ook dat je hem kunt uitlezen(pag. 53).
Verder is daisy-chain op een bus-systeem op zijn minst vreemd te noemen. Bij schuifregisters wordt het wel zo goed als altijd toegepast.
Dus niet naar een volgende aansluiten of andere fratsen, maar gewoon volgens de datasheet aansluiten zou ik adviseren.

Acties:
  • 0 Henk 'm!

  • huub8
  • Registratie: Maart 2009
  • Laatst online: 28-06-2021
Ik heb de SDI en SDO omgewisseld en het werkt perfect. Ik heb nog zo'n zelfde chip, om die aan dezelfde microcontroller te hangen moet ik dan gewoon een tweede pin gebruiken voor de chip select voor die chip (dus beide chips delen dezelfde verbindingen met de microcontroller op de chip select na)?

(de reden dat ik het fout had aangesloten was trouwens dat het wel zo staat uitgebeeld op pagina 59, maar dat is blijkbaar voor iets anders)

[ Voor 19% gewijzigd door huub8 op 28-04-2012 00:43 ]


Acties:
  • 0 Henk 'm!

  • AlexanderB
  • Registratie: Maart 2007
  • Laatst online: 09-05 19:05

AlexanderB

7800 rpm

3xhaas schreef op zaterdag 28 april 2012 @ 00:34:
[...]

Bij dit device staat er toch in de datasheet dat je SDI>SDO en vice versa moet aansluiten(pag. 41) en ook dat je hem kunt uitlezen(pag. 53).
Verder is daisy-chain op een bus-systeem op zijn minst vreemd te noemen. Bij schuifregisters wordt het wel zo goed als altijd toegepast.
Dus niet naar een volgende aansluiten of andere fratsen, maar gewoon volgens de datasheet aansluiten zou ik adviseren.
t kan op meerdere manieren.. ik had zelf n daisy chain, zodat je de hele riedel als 1 hele lange reeks uit kon sturen, met chip sel op alle chips gewoon geselecteerd..

je kan ze inderdaad parallel hangen, dat is de officiële methode, en dan per chip de chip select aansturen voordat je de waarde aanpast. als je telkens maar 1 tegelijk hoeft aan te passen...

Acties:
  • 0 Henk 'm!

  • huub8
  • Registratie: Maart 2009
  • Laatst online: 28-06-2021
Het hele gebeuren gaat uiteindelijk worden gebruikt voor het aansturen van een Xbox, deze chips moeten de analoge sticks vervangen. Ze worden dan aangestuurd door een 18f4550, die de data krijgt van een computer over USB. Dit moet gehandicapte mensen instaat stellen om via middelen as face tracking de xbox te besturen.
Ik heb het al werkend gekregen doormiddel van een "pwm dac", maar dan had ik extra microcontrollers nodig gehad (voor de benodigde pwm kanalen) en dus leek mij dit een mooie relatief goedkope maar goedwerkende oplossing.

De software stuurt dan om de zoveel millisecondes de nieuwe waardes naar de chip, waaronder dus de waardes voor deze twee chips.

(maar als iemand hier een beter idee voor heeft hoor ik het natuurlijk graag, het oorspronkelijke project waar dit project uit voortgekomen is is trouwen hier te vinden, maar dit was nog niet op het helpen van gehandicapte mensen gericht)

[ Voor 27% gewijzigd door huub8 op 28-04-2012 01:09 ]


Acties:
  • 0 Henk 'm!

  • 3xhaas
  • Registratie: Februari 2002
  • Laatst online: 26-09-2024
AlexanderB schreef op zaterdag 28 april 2012 @ 00:58:
[...]

t kan op meerdere manieren.. ik had zelf n daisy chain, zodat je de hele riedel als 1 hele lange reeks uit kon sturen, met chip sel op alle chips gewoon geselecteerd..

je kan ze inderdaad parallel hangen, dat is de officiële methode, en dan per chip de chip select aansturen voordat je de waarde aanpast. als je telkens maar 1 tegelijk hoeft aan te passen...
Je hebt gelijk. De CS pin is blijkbaar een 3-state pin. En om het device uit te lezen moet je hem ~2x zo hoog als een normaal hoog signaal maken.
Je hebt dus:
V(IH) = Vdd, idle state
V(IL) = Vss, write mode
V(IHH) = ~2x Vdd, read mode
Ik kan niet specifiek terugvinden dat hij ook het huidige bitje uitstuurt, maar wel dat hij ook wordt aangestuurd bij V(IL). Het lijkt me dus wel vrij logisch als dat gebeurt.
Mocht je echter gebruik willen maken om de registers of de status van de error bit uit te lezen, dan zul je de SDO van je device naar de SDI van je MCU moeten connecten en inderdaad ieder device met een eigen CS moeten aansturen.
Wil je dat allemaal niet dan kun je ze waarschijnlijk in daisy-chain zetten en met een CS aansturen.
Op pagina 60 staan nog twee manieren om V(IHH) te maken.

Acties:
  • 0 Henk 'm!

  • Stoney3K
  • Registratie: September 2001
  • Laatst online: 11-10 01:22

Stoney3K

Flatsehats!

huub8 schreef op vrijdag 27 april 2012 @ 23:09:
Zelf een software spi maken lijkt mij wat te ingewikkeld...
Ingewikkeld? Een constante trein pulsen als klok maken en de SDO togglen op de waarde van je data (synchroon met die klok) is echt niet meer dan 10 regels code.

Je klok hoeft namelijk ook niet te blijven lopen als CS hoog is.

Zet het daar maar neer! -- It's time to party like it's 1984 -- Soundcloud

Pagina: 1