0
\$\begingroup\$

I'm currently working on a project for which I need to control 16 white LEDs with two shift registers 74HC595 in cascade. I work on a SAMD21 XPLAINED PRO board (µC samd21j18a) and ATMEL Studio as IDE.

I want to send data to the shift registers through SPI. I manage to do it using ATMEL Start to define my configuration but I want to do it with ASF to optimize my code and to get a better control / understanding of it.

Based on samd21j18a datasheet and on different tutorials I found, I tried to do it but for the moment it doesn't work.

#include <asf.h>

#define SLAVE_SELECT_PIN    EXT1_PIN_SPI_SS_0 // Shift register's latch pin on PA05
#define BUFFER_LENGTH       16 // 16 bits message
#define MESSAGE_SIZE        2

uint8_t spi_transfet_array[MESSAGE_SIZE]; // Create a buffer to send through SPI
unsigned char en_pin = IOPORT_CREATE_PIN(1, 9); // Enable pin

struct spi_module spi_master_instance;
struct spi_slave_inst slave;

void spi_configuration(void);
void spi_send_message(uint16_t data);

int main (void)
{
    system_init();
    delay_init();
    spi_configuration();
    
    ioport_set_pin_dir(en_pin, IOPORT_DIR_OUTPUT); // Set enable pin as OUTPUT
    
    while (1) {
        spi_send_message(0b0001100010010000);
    }
}

void spi_configuration(void){
    struct spi_config master_config;
    struct spi_slave_inst_config slave_config;
    
    /*
     * With config by defaults, mux_setting is SPI_SIGNAL_MUX_SETTING_D
     *
     * Based on samd21 datasheet 26.6 "Data In Pinout" :
     * DIPO 0x3 : 
     * - DI on SERCOM0 PAD[3] (PA07)
     *
     * Based on samd21 datasheet 26.7 "Data Out Pinout" :
     * DOP0 0x0 :
     * - DO on SERCOM0 PAD[0] (PA04)
     * - SCK on SERCOM0 PAD[1] (PA05)
     * - SS on SERCOM0 PAD[2] (PA06)
     */
    spi_get_config_defaults(&master_config);
    
    master_config.pinmux_pad0 = EXT1_SPI_SERCOM_PINMUX_PAD0; // MOSI PA04 (Shift register's data pin)
master_config.pinmux_pad1 = EXT1_SPI_SERCOM_PINMUX_PAD1; // SCK PA05 (Shift register's clock pin)
master_config.pinmux_pad2 = EXT1_SPI_SERCOM_PINMUX_PAD2; // Slave Selection PA06 (Shift register's latch pin)
master_config.pinmux_pad3 = EXT1_SPI_SERCOM_PINMUX_PAD3; // MISO PA07 (unused here)
    
    spi_slave_inst_get_config_defaults(&slave_config);
    slave_config.ss_pin = SLAVE_SELECT_PIN;
    
    spi_init(&spi_master_instance, EXT1_SPI_MODULE, &master_config);
    spi_attach_slave(&slave, &slave_config);
    
    spi_enable(&spi_master_instance);
}

void spi_send_message(uint16_t data){
    // Create message to send through SPI
    spi_transfet_array[0] = data >> 8;
    spi_transfet_array[1] = data & 0xFF;
        
    ioport_set_pin_level(en_pin, false); // Set enable pin LOW
    spi_select_slave(&spi_master_instance, &slave, true); // Enable slave selection
    spi_write_buffer_wait(&spi_master_instance, spi_transfet_array, BUFFER_LENGTH); // Send message
    spi_select_slave(&spi_master_instance, &slave, false); // Disable slave selection;
    ioport_set_pin_level(en_pin, true); // Set enable pin HIGH
    delay_ms(1); // Debounce time
    ioport_set_pin_level(en_pin, false); // Set enable pin LOW;
}

EDIT : A schematic of my assembly : Schematic

I've tried to do it in different ways but I don't manage to get a good result. That's the first time I work with SPI and I'm really not sure to do it correctly (especially the mux configuration).

I use the SERCOM0 for which the PADS 0, 1, 2 and 3 are PA04, PA05, PA06 and PA07

My mux configuration is SPI_SIGNAL_MUX_SETTING_D (default mux config) which means DOPO: 0x0, DIPO: 0x3

EDIT : Due to a misreading of the technical documentation I had initially made a connection error which I have now corrected (the problem persists however). See below the new connexions.

Default Mux config

Data In Pinout

Data Out Pinout

I/O Multiplexing

My connexions are :

Data pin (MOSI) : `PA04`,
Enable pin : `PB09`,
Latch pin (SS pin) : `PA06`,
Clock pin (SCK pin) : `PA05`.

Do you have any idea of what could be wrong ?

\$\endgroup\$
11
  • 1
    \$\begingroup\$ What does "I don't manage to get a good result" mean? Explain what doesn't work as expected and we may be able to help. \$\endgroup\$
    – Finbarr
    Mar 29, 2022 at 17:48
  • \$\begingroup\$ The CD74HC595 will work at 3.3v and less and it should work when connected directly with your microcontroller. However, you may run into some problems if you are using a 5v supply for the cd74HC595 and operating the microcontroller at a lower supply voltage. Also, make sure the ground wires of both are connected to each other. \$\endgroup\$ Mar 29, 2022 at 20:41
  • \$\begingroup\$ @Finbarr : "I don't manage to get a good result" actually means that I don't manage to control the LEDs which are connected to the shift register. I can't really tell you more than that because for the moment my message doesn't seems to be sent correctly to the shift register and the LEDs don't turn on. \$\endgroup\$
    – Fanch
    Mar 30, 2022 at 8:39
  • \$\begingroup\$ @GT Electronics : On CD74HC595 datasheet it's written "Wide operating voltage range of 2 V to 6 V" so I don't reallly understand why it should only work with 3.3V ? Moreover as I say in my question it worked perfectly when I used ATMEL Start to define my configuration. So I don't think that the problem comes from an hardware incompatibility. \$\endgroup\$
    – Fanch
    Mar 30, 2022 at 8:42
  • \$\begingroup\$ @Solomon Slow : Yes, you're right, I think I should use a logic analyzer. I'll probably look into buying one. (Actually i'm looking for it but it's quite expensive...) May be I can do it with the embedded debugger which is on the SAMD21XPLAINED PRO board. \$\endgroup\$
    – Fanch
    Mar 30, 2022 at 9:07

1 Answer 1

1
\$\begingroup\$

I found the problem... My buffer is constituted of two 8 bits elements and when I send my message through SPI I used to do :

spi_write_buffer_wait(&spi_master_instance, spi_transfet_array, BUFFER_SIZE); 
// With BUFFER_SIZE = 16

but what I had to do is :

spi_write_buffer_wait(&spi_master_instance, spi_transfet_array, MESSAGE_SIZE);
// With MESSAGE_SIZE = 2

I'm now able to control the LEDs I wand to turn on or off with the two shift registers in cascade and through the SPI bus.

The only problem I had was that my LEDs were shining very weakly. To solve this problem I had to decrease my baudrate to 50 000 and the problem was fixed (the default config takes a baudrate at 100 000).

The complete code : (I changed few parameters)

#include <asf.h>

#define SLAVE_SELECT_PIN    EXT1_PIN_SPI_SS_0 // Shift register's latch pin on PA05
#define MESSAGE_SIZE        2

uint8_t spi_transfet_array[MESSAGE_SIZE]; // Create a buffer to send through SPI
unsigned char en_pin = IOPORT_CREATE_PIN(1, 9); // Set enable pin as PB09

struct spi_module spi_master_instance;
struct spi_slave_inst slave;

void spi_configuration(void);
void spi_send_message(uint16_t data);

int main (void)
{
    system_init();
    delay_init();
    spi_configuration();
    
    ioport_set_pin_dir(en_pin, IOPORT_DIR_OUTPUT); // Set enable pin as OUTPUT
    
    while (1) {
        spi_send_message(0b1000000000000001);
    }
}

void spi_configuration(void){
    struct spi_config master_config;
    struct spi_slave_inst_config slave_config;
    

    spi_get_config_defaults(&master_config);
    
    /*
     * With mux_setting is SPI_SIGNAL_MUX_SETTING_E
     *
     * Based on samd21 datasheet 26.6 "Data In Pinout" :
     * DIPO 0x0 : 
     * - DI on SERCOM0 PAD[0] (PA04)
     *
     * Based on samd21 datasheet 26.7 "Data Out Pinout" :
     * DOP0 0x1 :
     * - DO on SERCOM0 PAD[2] (PA06)
     * - SCK on SERCOM0 PAD[3] (PA07)
     * - SS on SERCOM0 PAD[1] (PA05)
     */
    master_config.mux_setting = SPI_SIGNAL_MUX_SETTING_E;
    master_config.pinmux_pad0 = EXT1_SPI_SERCOM_PINMUX_PAD0; // MISO PA04 (unused here)
    master_config.pinmux_pad1 = EXT1_SPI_SERCOM_PINMUX_PAD1; // Slave Selection PA05 (Shift register's latch pin)
    master_config.pinmux_pad2 = EXT1_SPI_SERCOM_PINMUX_PAD2; // MOSI PA06 (Shift register's data pin)
    master_config.pinmux_pad3 = EXT1_SPI_SERCOM_PINMUX_PAD3; // SCK PA07 (Shift register's clock pin)

    master_config.data_order = SPI_DATA_ORDER_LSB;
    master_config.mode_specific.master.baudrate = 50000;
    
    spi_slave_inst_get_config_defaults(&slave_config);
    slave_config.ss_pin = SLAVE_SELECT_PIN;
    
    spi_init(&spi_master_instance, EXT1_SPI_MODULE, &master_config);
    spi_attach_slave(&slave, &slave_config);
    
    spi_enable(&spi_master_instance);
}

void spi_send_message(uint16_t data){
    // Create message to send through SPI
    spi_transfet_array[1] = data >> 8;
    spi_transfet_array[0] = data & 0xFF;
        
    ioport_set_pin_level(en_pin, false); // Set enable pin LOW
    spi_select_slave(&spi_master_instance, &slave, true); // Enable slave selection
    spi_write_buffer_wait(&spi_master_instance, spi_transfet_array, MESSAGE_SIZE); // Send message
    spi_select_slave(&spi_master_instance, &slave, false); // Disable slave selection
    ioport_set_pin_level(en_pin, true); // Set enable pin HIGH
    delay_ms(1); // Debounce time
    ioport_set_pin_level(en_pin, false); // Set enable pin LOW
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.