APA102 with atmeaga328 problem

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

I have a problem about write a code to communicate with APA102 (8 led) with atmeaga328. I wrote a code that can set led color with specific led when i have one set of color it work fine, but if i have 2 set of colors. it struck at first set of color and does't change the set of color on led . I don't know what wrong with the code. Can you check it for me ?

#define F_CPU 8000000L

#define CS PB2
#define MOSI PB3
#define CLK PB5

#include <avr/io.h>
#include <util/delay.h>

typedef struct RGBColor {
    uint8_t brightness;
    uint8_t red;
    uint8_t green;
    uint8_t blue;
} RGBColor_t;

/* Return a RGBColor from a 32-bit hex color */
inline RGBColor_t rgb(const uint32_t color) {
    uint8_t brightness = color >> 24;
    uint8_t red = ((color & 0x00ff0000) >> 16);
    uint8_t green = ((color & 0x0000ff00) >> 8);
    uint8_t blue = color & 0x0000ff;
    RGBColor_t c = {brightness, red, green, blue };
    return c;
}

RGBColor_t RED = { 0xfe, 0x7f, 0x00, 0x00 };
RGBColor_t GREEN = { 0xfe, 0x00, 0x00, 0x7f };
RGBColor_t BLUE = { 0xff, 0x00, 0x00, 0x7f };
RGBColor_t BLACK = { 0xe0, 0x00, 0x00, 0x00 };

void USART_Init(unsigned int ubrr) {
    /* Set baud rate */
    UBRR0 = ubrr;
    /* Double Transmission Speed*/
    UCSR0A |= (1 << U2X0);
    /* Enable receiver and transmitter */
    UCSR0B |= (1 << RXEN0)|(1 << TXEN0);
    /* Set frame format: 8data */
    UCSR0C |= (1 << UCSZ01)|(1 << UCSZ00);
}

void USART_Transmit( unsigned char data ) {
    /* Wait for empty transmit buffer */
    while ( !( UCSR0A & (1 << UDRE0)) ) ;
    /* Put data into buffer, sends the data */
    UDR0 = data;
}

void print(unsigned char *buffer) {
    for(int i=0; buffer[i] != 0; i++){
        USART_Transmit(buffer[i]);
    }
}

unsigned char USART_Receive() {
    /* Wait for data to be received */
    while ( !(UCSR0A & (1 << RXC0)) ) ;
    /* Get and return received data from buffer */
    return UDR0;
}

void SPI_Init()
{   
    /* Set MOSI CLK CS as Output*/
    DDRB |= (1 << CLK) | (1 << CLK) | (1 << MOSI);
    /* Set MOSI CS as HIGH*/
    PORTB |= (1 << CS);
    PORTB |= (1 << MOSI);
    // set clock polarity/phase to mode 3
    SPCR |= (1 << CPOL);
    /* Enable SPI, Master mode, set clock scale to 1/16 */
    SPCR |= (1 << SPE) | (1 << MSTR) | (1 << SPR0);
}


void trasmitSPI(uint8_t data){
    SPDR = data;                  // Put data to SPDR
    while(!(SPSR & (1<<SPIF)));   // wait for SPIF high 
}

void startAPA102(){
    for(uint8_t i=0;i<4;i++){
        trasmitSPI(0x00);
    }
}

void endAPA102(){
    trasmitSPI(0xf0);
}

void setLEDColor(const RGBColor_t color){
    trasmitSPI(color.brightness);
    trasmitSPI(color.blue);
    trasmitSPI(color.green);
    trasmitSPI(color.red);
}

void writeAPA102(RGBColor_t *led){
    PORTB &= ~(1 << CS);
    /* Start Frame APA102*/
    startAPA102();
    
    /* Write data frame for 8 led*/
    for(uint8_t i=0;i<8;i++){
        setLEDColor(led[i]);
    }
    
    /* End Frame APA102*/
    endAPA102();
    PORTB |= (1 << CS);
    _delay_ms(100);
}

int main(void) {
    
    USART_Init(103);
    // unsigned char buffer[] = "Hello Tae\r\n";
    SPI_Init();
    RGBColor_t led[8] = {RED, RED, GREEN, GREEN, BLUE, BLUE, BLACK, BLACK};
    RGBColor_t led2[8] = {BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK};
    DDRB |= (1 << PB0);
    while (1) {
        writeAPA102(led);
        _delay_ms(500);
        writeAPA102(led2);
        _delay_ms(500);
        //unsigned char received_char = USART_Receive();
        //if (received_char == 0x000D){
        //    print(buffer); 
        //}
    }
}

 

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

entropy01 wrote:
when i have one set of color it work fine, but if i have 2 set of colors. it struck at first set of color and does't change the set of color on led . I don't know what wrong with the code.

Not sure what you mean by that - please could you expand / clarify ?

 

Do you have a debugger to see what's happening?

 

Wait a minute ... 

 

RGBColor_t RED = { 0xfe, 0x7f, 0x00, 0x00 };
RGBColor_t GREEN = { 0xfe, 0x00, 0x00, 0x7f };
RGBColor_t BLUE = { 0xff, 0x00, 0x00, 0x7f };
RGBColor_t BLACK = { 0xe0, 0x00, 0x00, 0x00 };

So these are initialised structures

 

    RGBColor_t led[8] = {RED, RED, GREEN, GREEN, BLUE, BLUE, BLACK, BLACK};
    RGBColor_t led2[8] = {BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK};

So does this actually work?

 

Should they not be pointers to the structures?

 

EDIT

 

On 2nd thoughts, probably OK.

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
Last Edited: Tue. May 4, 2021 - 07:13 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

DDRB |= (1 << CLK) | (1 << CLK) | (1 << MOSI);

DO you see anything wrong above?

John Samperi

Ampertronics Pty. Ltd.

https://www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

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


I ran the code in one of my custom boards designed for up to 4 channels SPI LED strips but unfortunately I don't have any of those LED strip around, the one I have is using the LPD8806 LEDs, they are SPI but different so could not do a full test.

 

 

However the clock and data lines are sending stuff out every 500ms as they are supposed to.

 

NOTE: The post above shows that you have the CLK setup twice but not the CS pin. So most likely as soon as you send something out the SPI gets a collision error and revert to slave.

John Samperi

Ampertronics Pty. Ltd.

https://www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

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

I apologize for the delay in responding to your question. I try to make a running led with APA102. I read APA102's datasheet and code from internet and still struck. Can someone help me

This is my lastest code

#define F_CPU 16000000UL

#include <avr/interrupt.h>
#include <avr/io.h>
#include <util/delay.h>

#define CS PB2
#define MOSI PB3
#define CLK PB5

#define nop() asm volatile(" nop \n\t")

typedef struct RGBColor {
    uint8_t brightness;
    uint8_t red;
    uint8_t green;
    uint8_t blue;
} RGBColor_t;

/* Return a RGBColor from a 32-bit hex color */
inline RGBColor_t rgb(const uint32_t color) {
    uint8_t brightness = color >> 24;
    uint8_t red = ((color & 0x00ff0000) >> 16);
    uint8_t green = ((color & 0x0000ff00) >> 8);
    uint8_t blue = color & 0x0000ff;
    RGBColor_t c = {brightness, red, green, blue };
    return c;
}

RGBColor_t RED = { 31, 255, 0, 0 };
RGBColor_t GREEN = { 31, 0, 255, 0 };
RGBColor_t BLUE = { 31, 0, 0, 255 };
RGBColor_t BLACK = { 0, 0, 0, 0 };
RGBColor_t WHITE = { 31, 255, 255, 255 };

void USART_Init(unsigned int ubrr) {
    /* Set baud rate */
    UBRR0 = ubrr;
    /* Double Transmission Speed*/
    UCSR0A |= (1 << U2X0);
    /* Enable receiver and transmitter */
    UCSR0B |= (1 << RXEN0)|(1 << TXEN0);
    /* Set frame format: 8data */
    UCSR0C |= (1 << UCSZ01)|(1 << UCSZ00);
}

void USART_Transmit( unsigned char data ) {
    /* Wait for empty transmit buffer */
    while ( !( UCSR0A & (1 << UDRE0)) ) ;
    /* Put data into buffer, sends the data */
    UDR0 = data;
}

void print(unsigned char *buffer) {
    for(int i=0; buffer[i] != 0; i++){
        USART_Transmit(buffer[i]);
    }
}

unsigned char USART_Receive() {
    /* Wait for data to be received */
    while ( !(UCSR0A & (1 << RXC0)) ) ;
    /* Get and return received data from buffer */
    return UDR0;
}

void SPI_Init()
{
    DDRB |= (1 << MOSI);
    DDRB |= (1 << CLK);
    DDRB |= (1 << CS);

    // set mosi & ss to high
    PORTB |= (1 << MOSI);
    PORTB |= (1 << CS);

    // enable spi
    SPCR |= (1 << SPE);

    // set as master
    SPCR |= 1 << MSTR;

    // set clock polarity/phase to mode 3
    SPCR |= (1 << CPOL) | (1 << CPHA);

    // set clock scale to 1/2
    SPSR |= 1 << SPI2X;
    SPCR |= (1 << SPR1) | (1 << SPR0);
}

void trasmitSPI(uint8_t data){
    SPDR = data;
    while (!(SPSR & (1 << SPIF))) {}
}

void startAPA102(){
    for(uint8_t i=0;i<4;i++){
        trasmitSPI(0);
    }
}

void endAPA102(){
    trasmitSPI(0xf0);
}

void setLEDColor(const RGBColor_t color){
    trasmitSPI(0xe0+color.brightness);
    trasmitSPI(color.blue);
    trasmitSPI(color.green);
    trasmitSPI(color.red);
}

void writeAPA102(RGBColor_t L1, RGBColor_t L2, RGBColor_t L3, RGBColor_t L4, RGBColor_t L5, RGBColor_t L6, RGBColor_t L7, RGBColor_t L8){
    /* Start Frame APA102*/
    startAPA102();

    /* Write data frame for 8 led*/
    setLEDColor(L1);
    setLEDColor(L2);
    setLEDColor(L3);
    setLEDColor(L4);
    setLEDColor(L5);
    setLEDColor(L6);
    setLEDColor(L7);
    setLEDColor(L8);

    /* End Frame APA102*/
    endAPA102();
}

int main(void) {

    //USART_Init(103);
    // unsigned char buffer[] = "Hello Tae\r\n";
    SPI_Init();
    while (1) {
        writeAPA102(GREEN, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK);
        writeAPA102(BLACK, GREEN, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK);
        writeAPA102(BLACK, BLACK, GREEN, BLACK, BLACK, BLACK, BLACK, BLACK);
        writeAPA102(BLACK, BLACK, BLACK, GREEN, BLACK, BLACK, BLACK, BLACK);
        writeAPA102(BLACK, BLACK, BLACK, BLACK, GREEN, BLACK, BLACK, BLACK);
        writeAPA102(BLACK, BLACK, BLACK, BLACK, BLACK, GREEN, BLACK, BLACK);
        writeAPA102(BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, GREEN, BLACK);
        writeAPA102(BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, GREEN);
        //unsigned char received_char = USART_Receive();
        //if (received_char == 0x000D){
        //    print(buffer);
        //}
    }
}

I simulate the software in Proteus. I can set the led color ,but led light is not running.

 

 

Last Edited: Wed. May 5, 2021 - 04:00 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

entropy01 wrote:
I simulate the software in Proteus.

So what does that tell you?

 

You should be able to see the waveforms being generated - are they correct?

 

entropy01 wrote:

    DDRB |= (1 << MOSI);
    DDRB |= (1 << CLK);
    DDRB |= (1 << CS);

There's nothing wrong with combining those into a single assignment:

    DDRB |= (1 << MOSI) | (1 << CLK) | (1 << CS);

#3 was simply pointing out that you had the value wrong

 

In fact, it could probably be just an assignment - rather than a read-modify-write ...

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes, the waveforms  is generate, but it's not do as I expected.

writeAPA102(GREEN, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK);
writeAPA102(BLACK, GREEN, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK);
writeAPA102(BLACK, BLACK, GREEN, BLACK, BLACK, BLACK, BLACK, BLACK);
writeAPA102(BLACK, BLACK, BLACK, GREEN, BLACK, BLACK, BLACK, BLACK);
writeAPA102(BLACK, BLACK, BLACK, BLACK, GREEN, BLACK, BLACK, BLACK);
writeAPA102(BLACK, BLACK, BLACK, BLACK, BLACK, GREEN, BLACK, BLACK);
writeAPA102(BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, GREEN, BLACK);
writeAPA102(BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, GREEN);

From this part of code I expected the green light should move from left to right ,but it's not.

 

PS.

Yes it's a assignment and I didn't just copy and paste. I read the datasheet and the blog who work with apa102 ,but I still struck what wrong with my code for a week..

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

entropy01 wrote:
but it's not do as I expected.
So what does happen?

 

Also, as Proteus is a simulator/debugger what actually happens as you step those lines one by one ?

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

entropy01 wrote:
but it's not do as I expected.

So what did you expect?

How, exactly, did it differ from that?

 

Look at what's happening as you step through the code - see where the differences are happening.

 

I expected the green light should move from left to right ,but it's not.

Again: what, exactly, is happening?

 

Debugging is a key part of development - it doesn't just stop at writing the code: https://www.avrfreaks.net/commen...

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
Last Edited: Wed. May 5, 2021 - 05:07 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'm allergic to Proteus and only work with real hardware. wink

John Samperi

Ampertronics Pty. Ltd.

https://www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly