PROGMEM tricks

sadman41
Offline
Зарегистрирован: 19.10.2016

Порой очень хочется изменить значение переменной, расположенной в области PROGMEM. 

Это можно сделать вот так, например: https://mon.im/2014/11/modifying-avr-progmem-at-runtime.html

Но, я, как человек ленивый, Atmel Studio ставить не хочу, считать всякие фьюзы - тоже. Поэтому буду менять PROGMEM скетчем, созданным прямо в Arduino IDE. Так как изменение данных в PROGMEM  доступно только из области бутлоадера, без дополнительных телодвижений, конечно, не обойтись, т. Но для человека, умеющего копировать файлы, обладающего USBasp и пятью минутами времени, нет ничего невозможного.

Итак:

1) берем специально обученный optiboot: https://raw.githubusercontent.com/majekw/optiboot/master/optiboot/bootloaders/optiboot/optiboot_atmega328.hex
2) Вжигаем бутлоадер в вашу Uno/Nano/Pro mini через Arduino IDE;
3) Компилируем и загружаем демку (файлы ниже);
...
42) Profit!

PROGMEM change demo
System is not registered. Enter registration name: SuperUser 

Erasing flash page
Writing to temporary flash buffer
Writing buffer to flash
Write done, reset MCU

PROGMEM change demo
System is registered to: SuperUser 
PROGMEM change demo
System is registered to: SuperUser 

progmem_change.ino:
 

#include "optiboot.h"
#include <avr/pgmspace.h>

const char registrationInfo[SPM_PAGESIZE] __attribute__ (( aligned(SPM_PAGESIZE) )) PROGMEM = {'\0'};

uint8_t workBuffer[SPM_PAGESIZE];

void printRegistrationInfo() {
  for (uint16_t i = 0x00; SPM_PAGESIZE > i; i++) {
    uint8_t currentByte = pgm_read_byte(&registrationInfo[i]);
    if (!currentByte) {
      return;
    }
    Serial.write(currentByte);
  }
}

void doRegistration() {
  uint16_t i = 0x00, data = 0x00;
  uint8_t currentByte = 0x00;

  // Take info
  while ((SPM_PAGESIZE - 1) > i && currentByte != '\n') {
    if (0x00 < Serial.available()) {
      currentByte = Serial.read();
      Serial.write(currentByte);
      workBuffer[i] = currentByte;
      i++;
    }
  }
  workBuffer[i] = '\0';
  delay(100);

  // Erasing FLASH page
  Serial.println(F("\nErasing flash page"));
  // wait for sending all text via serial
  delay(100);
  optiboot_page_erase((optiboot_addr_t)(void*) &registrationInfo[0]);

  // Copy RAM buffer to temporary flash buffer
  Serial.println(F("Writing to temporary flash buffer"));
  delay(100); // wait for sending all text via serial
  for (i = 0x00; SPM_PAGESIZE > i; i++) {
    if (!(i & 0x01)) { // we must write WORDs
      data = workBuffer[i];
    } else {
      data += ((uint16_t)workBuffer[i] << 8);
      optiboot_page_fill((optiboot_addr_t)(void*) &registrationInfo[i], data);
    }
  }
  // Writing temporary buffer to FLASH
  Serial.println(F("Writing buffer to flash"));
  delay(100); // wait for sending all text via serial
  optiboot_page_write((optiboot_addr_t)(void*) &registrationInfo[0]);
  Serial.println("Write done, reset MCU\n");
  delay(100); // wait for sending all text via serial
  asm volatile ("jmp 0");
}

void setup() {
  Serial.begin(115200);
  Serial.println(F("PROGMEM change demo"));

  Serial.print(F("System is "));
  if ('\0' == pgm_read_byte(&registrationInfo[0])) {
    Serial.print(F("not registered. Enter registration name: "));
    doRegistration();
  } else {
    Serial.print(F("registered to: "));
    printRegistrationInfo();
  }
}

void loop() {}

optiboot.h:


/* Optiboot 'header' file.
 * 
 * June 2015 by Marek Wodzinski, https://github.com/majekw
 * Released to public domain
 * 
 * This header file gives possibility to use SPM instruction
 * from Optiboot bootloader memory.
 *
 * There are 3 convenient functions available here:
 *  optiboot_page_erase - to erase FLASH page
 *  optiboot_page_fill - to put words into temporary buffer
 *  optiboot_page_write - to write contents of temporary buffer into FLASH
 *
 * For some hardcore users, you could use 'do_spm' as raw entry to
 * bootloader spm function.
 */

#ifndef _OPTIBOOT_H_
#define _OPTIBOOT_H_  1

#include <avr/boot.h>

/* 
 * Main 'magic' function - enter to bootloader do_spm function
 *
 * address - address to write (in bytes) but must be even number
 * command - one of __BOOT_PAGE_WRITE, __BOOT_PAGE_ERASE or __BOOT_PAGE_FILL
 * data - data to write in __BOOT_PAGE_FILL. In __BOOT_PAGE_ERASE or 
 *          __BOOT_PAGE_WRITE it control if boot_rww_enable is run
 *         (0 = run, !0 = skip running boot_rww_enable)
 *
 *
 * Contents of bootloader's do_spm function, just for reference:
 *
 * static void do_spm(uint16_t address, uint8_t command, uint16_t data) {
 *     // Do spm stuff
 *     asm volatile (
 * 	 "    movw  r0, %3\n"
 *       "    out %0, %1\n"
 *       "    spm\n"
 *       "    clr  r1\n"
 *       :
 *       : "i" (_SFR_IO_ADDR(__SPM_REG)),
 *         "r" ((uint8_t)command),
 *         "z" ((uint16_t)address),
 *         "r" ((uint16_t)data)
 *       : "r0"
 *     );
 * 
 *     // wait for spm to complete
 *     //   it doesn't have much sense for __BOOT_PAGE_FILL,
 *     //   but it doesn't hurt and saves some bytes on 'if'
 *     boot_spm_busy_wait();
 * #if defined(RWWSRE)
 *     // this 'if' condition should be: (command == __BOOT_PAGE_WRITE || command == __BOOT_PAGE_ERASE)...
 *     // but it's tweaked a little assuming that in every command we are interested in here, there
 *     // must be also SELFPRGEN set. If we skip checking this bit, we save here 4B
 *     if ((command & (_BV(PGWRT)|_BV(PGERS))) && (data == 0) ) {
 *       // Reenable read access to flash
 *       boot_rww_enable();
 *     }
 * #endif
 * }
 *
 */

/*
 * This 'typedef' (in following line) and 'const' (few lines below) are a way to define external function at some arbitrary address
 */
typedef void (*do_spm_t)(uint16_t address, uint8_t command, uint16_t data);

/*
 * Devices with 64KB of flash or more have larger bootloader area (1KB) (they are BIGBOOT targets),
 * so entry address in these chips is different from smaller ones.
 */
#if FLASHEND > 65534
  const do_spm_t do_spm = (do_spm_t)((FLASHEND-1023+2)>>1);
#else
  const do_spm_t do_spm = (do_spm_t)((FLASHEND-511+2)>>1);
#endif

/*
 * Devices with more than 64KB of flash:
 * - have RAMPZ register :-) 
 * - need larger variable to hold address (pgmspace.h uses uint32_t)
 * 
 * To not do many ifdefs and don't confuse users I declared new 'always valid'
 * type to declare address: optiboot_addr_t.
 */
#ifdef RAMPZ
  typedef uint32_t optiboot_addr_t;
#else
  typedef uint16_t optiboot_addr_t;
#endif

/*
 * The same as do_spm but with disable/restore interrupts state
 * required to succesfull SPM execution
 * 
 * On devices with more than 64kB flash, 16 bit address is not enough,
 * so there is also RAMPZ used in that case.
 */

void do_spm_cli(optiboot_addr_t address, uint8_t command, uint16_t data) {
  uint8_t sreg_save;

  sreg_save = SREG;  // save old SREG value
  asm volatile("cli");  // disable interrupts
  #ifdef RAMPZ
    RAMPZ=(address>>16) & 0xff;  // address bits 23-16 goes to RAMPZ
    do_spm((address & 0xffff),command,data); // do_spm accepts only lower 16 bits of address
  #else
    do_spm(address,command,data);  // 16 bit address - no problems to pass directly
  #endif
  SREG=sreg_save; // restore last interrupts state
}

/*
 * Erase page in FLASH
 */
void optiboot_page_erase(optiboot_addr_t address) {
  do_spm_cli(address,__BOOT_PAGE_ERASE,0);
}


/*
 * Write word into temporary buffer
 */
void optiboot_page_fill(optiboot_addr_t address, uint16_t data) {
  do_spm_cli(address,__BOOT_PAGE_FILL,data);
}


/*
 * Write temporary buffer into FLASH
 */
void optiboot_page_write(optiboot_addr_t address) {
  do_spm_cli(address,__BOOT_PAGE_WRITE,0);
}

#endif /* _OPTIBOOT_H_ */

Все благодарности отсылаем Marek Wodzinski. Ну и мне немножко за переработанную демку.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

ЕвгенийП пишет:

Спасибо. Я уже решил - вообще не на Си - ни на каком :)

Может, суржик? :)

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

А тема-то, кстати, весьма качественная. Да-а-а, и "в нашу гавань заходили корабли" :-)

sadman41
Offline
Зарегистрирован: 19.10.2016

Вам захотелось вывести на ленту пиксельных светодиодов что-то как не поддающееся математическому описанию, так и не являющееся полнейшим хаосом по рандомайзу, посему сохранённое в PROGMEM?

Вывод через FastLED или Adafruit Neopixel с перегрузкой данных из PROGMEM в RAM тосклив, безрадостен и тратит драгоценный ресурс контроллера?

Выход есть - прямой стриминг через LPM на страйп! Отщипнем кусочек от библиотеки Adafruit Neopixel, плюнем, дунем, кое-что заменим и вуаля:

Sketch uses 1106 bytes (3%) of program storage space. Maximum is 30720 bytes.
Global variables use 9 bytes (0%) of dynamic memory, leaving 2039 bytes for local variables. Maximum is 2048 bytes.
 
// LED bar on pin 6
uint8_t dataPin = 6;

// 3 frame for 8 LED bar
const byte frame[][24] PROGMEM = {
  // GR BB RG
  {
    0xFF, 0x00, 0x00,
    0x00, 0xFF, 0x00,
    0x00, 0x00, 0x00,
    0x00, 0x00, 0xFF,
    0x00, 0x00, 0xFF,
    0x00, 0x00, 0x00,
    0x00, 0xFF, 0x00,
    0xFF, 0x00, 0x00
  },
  // RG BB GR
  {
    0x00, 0xFF, 0x00,
    0xFF, 0x00, 0x00,
    0x00, 0x00, 0x00,
    0x00, 0x00, 0xFF,
    0x00, 0x00, 0xFF,
    0x00, 0x00, 0x00,
    0xFF, 0x00, 0x00,
    0x00, 0xFF, 0x00,
  },
  // RB GG BR
  {
    0x00, 0xFF, 0x00,
    0x00, 0x00, 0xFF,
    0x00, 0x00, 0x00,
    0x00, 0xFF, 0x00,
    0x00, 0xFF, 0x00,
    0x00, 0x00, 0x00,
    0x00, 0x00, 0xFF,
    0x00, 0xFF, 0x00,
  }
};

uint32_t pause = 500;


#define arraySize(_array) ( sizeof(_array) / sizeof(*_array) )

// Push bits to stripe 
static void WS2812bOut_P(const uint8_t _dataPin, const uint8_t* _data, uint16_t _dataSize)  {
  volatile uint8_t hi, lo, next, currentBit = 0x08, *port, *ptrData = (volatile uint8_t*)_data;
  uint8_t pinMask;

  port    = portOutputRegister(digitalPinToPort(_dataPin));
  pinMask = digitalPinToBitMask(_dataPin);

  hi = *port |  pinMask;
  lo = *port & ~pinMask;
  next = lo;
  /*
    // WS2812 RESET command
    digitalWrite(dataPin, LOW);
    delayMicroseconds(50);
  */
  // Some kind of magic here, thanx to Adafruit Neopixel source
  noInterrupts();
  asm volatile (
    "lpm  r0,  Z+"              "\n\t"
    "head20P:"                  "\n\t"
    "st   %a[port],  %[hi]"     "\n\t"
    "sbrc r0,  7"               "\n\t"
    "mov  %[next], %[hi]"       "\n\t"
    "dec  %[bit]"               "\n\t"
    "st   %a[port],  %[next]"   "\n\t"
    "mov  %[next] ,  %[lo]"     "\n\t"
    "breq nextbyte20P"          "\n\t"
    "rol  r0"                   "\n\t"
    "rjmp .+0"                  "\n\t"
    "nop"                       "\n\t"
    "st   %a[port],  %[lo]"     "\n\t"
    "nop"                       "\n\t"
    "rjmp .+0"                  "\n\t"
    "rjmp head20P"              "\n\t"
    "nextbyte20P:"              "\n\t"
    "ldi  %[bit]  ,  8"         "\n\t"
    "lpm  r0,  Z+"              "\n\t"
    "st   %a[port], %[lo]"      "\n\t"
    "sbiw %[count], 1"          "\n\t"
    "brne head20P"              "\n\t"  
    : [port]  "+e" (port),
    [bit]     "+d" (currentBit),
    [next]    "+r" (next),
    [count]   "+w" (_dataSize)
    :         "z" (ptrData),
    [hi]      "r" (hi),
    [lo]      "r" (lo)
  );
  interrupts();
}

void setup() {
  digitalWrite(dataPin, LOW);
  pinMode(dataPin, OUTPUT);
}

void loop() {
  for (uint8_t i = 0; arraySize(frame) > i; i++ ) {
    WS2812bOut_P(dataPin, frame[i], sizeof(frame[0x00]));
    delay(pause);
  }
}

Я не великий специалист в AVR assembler, так что если подправите - будет великолепно.

P.S. wdrakula, я помню, что array size модно через темплейт, но макрос ближе лежал.

lilik
Offline
Зарегистрирован: 19.10.2017

Минималистично получилось, а главное без буфера и ограничений.

/////////////////////////////////////
/// тест ws2812b 
////////////////////////////////////
#define line_ 33
uint8_t dataPin_1 = 6;
int dt=75;//
int t=400;//пауза
const byte k=7;//яркость
long Y=0;//
int n=0;//

/// GRB
const byte data_1[]PROGMEM  = {0,k,0, k,0,0, 0,0,k, k,k,0, 0,k,k, k,0,k  }; // палитра цветов
const byte data_2[line_*3]PROGMEM = {};// пусто-сброс   

void setup() {
 pinMode(dataPin_1, OUTPUT);
 pusto();
 }

void loop() {
	// эффект 1
 for(int i=1;i<(line_+1);i++){
  WS2812bOut_P(dataPin_1, &(data_1[3*0]),3*(1) );//красный
 }
 delay_(t); pusto();
  for(int i=1;i<(line_+1)/1.2;i++){
  WS2812bOut_P(dataPin_1, &(data_1[3*1]),3*(1) );//зелёный
 }
 delay_(t); pusto();
 for(int i=1;i<(line_+1)/1.5;i++){
  WS2812bOut_P(dataPin_1, &(data_1[3*2]),3*(1) );//синий
 }
 delay_(t); pusto();
  for(int i=1;i<(line_+1)/2;i++){
  WS2812bOut_P(dataPin_1, &(data_1[3*3]),3*(1) );//жёлтый
 }
 delay_(t); pusto();  
 for(int i=1;i<(line_+1)/3;i++){
  WS2812bOut_P(dataPin_1,&(data_1[3*4]),3*(1) );//сиреневый
 }
 delay_(t); pusto();
  for(int i=1;i<(line_+1)/5;i++){
  WS2812bOut_P(dataPin_1, &(data_1[3*5]),3*(1) );//голубой
 }
 delay_(t);  
 }
//////////////////////////////////////////////////////
#define arraySize(_array) ( sizeof(_array) / sizeof(*_array) )
// Push bits to stripe 
static void WS2812bOut_P(const uint8_t _dataPin, const uint8_t* _data, uint16_t _dataSize)  {
  volatile uint8_t hi, lo, next, currentBit = 0x08, *port, *ptrData = (volatile uint8_t*)(_data );
  uint8_t pinMask;

  port    = portOutputRegister(digitalPinToPort(_dataPin));
  pinMask = digitalPinToBitMask(_dataPin);

  hi = *port |  pinMask;
  lo = *port & ~pinMask;
  next = lo;
  /*
    // WS2812 RESET command
    digitalWrite(dataPin, LOW);
    delayMicroseconds(50);
  */
  // Some kind of magic here, thanx to Adafruit Neopixel source
  noInterrupts();
  asm volatile (
    "lpm  r0,  Z+"              "\n\t"
    "head20P:"                  "\n\t"
    "st   %a[port],  %[hi]"     "\n\t"
    "sbrc r0,  7"               "\n\t"
    "mov  %[next], %[hi]"       "\n\t"
    "dec  %[bit]"               "\n\t"
    "st   %a[port],  %[next]"   "\n\t"
    "mov  %[next] ,  %[lo]"     "\n\t"
    "breq nextbyte20P"          "\n\t"
    "rol  r0"                   "\n\t"
    "rjmp .+0"                  "\n\t"
    "nop"                       "\n\t"
    "st   %a[port],  %[lo]"     "\n\t"
    "nop"                       "\n\t"
    "rjmp .+0"                  "\n\t"
    "rjmp head20P"              "\n\t"
    "nextbyte20P:"              "\n\t"
    "ldi  %[bit]  ,  8"         "\n\t"
    "lpm  r0,  Z+"              "\n\t"
    "st   %a[port], %[lo]"      "\n\t"
    "sbiw %[count], 1"          "\n\t"
    "brne head20P"              "\n\t"  
    : [port]  "+e" (port),
    [bit]     "+d" (currentBit),
    [next]    "+r" (next),
    [count]   "+w" (_dataSize)
    :         "z" (ptrData),
    [hi]      "r" (hi),
    [lo]      "r" (lo)
  );
  interrupts();
}
//////////////////////////////////////////////////////
void delay_(int T){
  Y=millis(); 
 while(millis()-Y<T){
  }
// n++;if(n>100){n=0;t=t+10;if(t>40){t=10;}} 
}
/////////////////////////////////////
void pusto(){
 WS2812bOut_P(dataPin_1, &(data_2[0]),3*(line_) );//
 delayMicroseconds(dt);  
}
/////////////////////////////////////

 

sadman41
Offline
Зарегистрирован: 19.10.2016

Хочу предупредить последователей, что нет гарантии корректной работы последовательных вызовов функции битстрима для заполнения страйпа фрагментами массивов на всех платах с AVR. На моей Freeduino иногда выходят странные спецэффекты.

Вывод одного массива работает, в этом я более-менее уверен. Только не забывайте о том, что перед началом вывода нужно сделать сброс чипу WS2818 через установку состояния LOW на DIN в течении 50мкс минимум.

И я против замены православного delay на конструкцию с millis().

lilik
Offline
Зарегистрирован: 19.10.2017

sadman41 пишет:
И я против замены православного delay на конструкцию с millis().

Сделал скетч на 4 эффекта, вернул delay, проверил на уно с мелким чипом и на про мини 168 с ещё более мелким. Просьба: граждане-товарищи, у кого есть ленты, ардуины и возможности, проверьте пожалуйста скетч на предмет корректной работы последовательных вызовов функции битстрима с убранным сбросом чипа ws2812b, а то ОЧЕНЬ надоели "штатные библиотеки" со скрытым пожиранием динамической памяти ( когда в скетче используется только 70 процентов дин. памяти, а он не работает ).

/////////////////////////////////////
/// тест ws2812b
////////////////////////////////////
#define line_ 33
uint8_t dataPin_1 = 6;
int dt = 75; //
int t = 30; //пауза
const byte k = 7; //яркость
long Y = 0; //


/// GRB
const byte data_1[]PROGMEM  = {0, k, 0, k, 0, 0, 0, 0, k, k, k, 0, 0, k, k, k, 0, k  }; // палитра цветов
const byte data_2[line_ * 3]PROGMEM = {}; // пусто-сброс

void setup() {
  pinMode(dataPin_1, OUTPUT);
  pusto();
}

void loop() {
  // эффект 1
  for (int j = 0; j < 6; j++) {
    for (int i = 1; i < (line_ + 1); i++) {
      WS2812bOut_P(dataPin_1, &(data_2[3 * 0]), 3 * i); //пусто
      WS2812bOut_P(dataPin_1, &(data_1[3 * j]), 3 * (1) ); //перебор цветов
      WS2812bOut_P(dataPin_1, &(data_1[3 * j]), 3 * (1) );
      WS2812bOut_P(dataPin_1, &(data_1[3 * j]), 3 * (1) );
      WS2812bOut_P(dataPin_1, &(data_1[3 * j]), 3 * (1) );
      WS2812bOut_P(dataPin_1, &(data_1[3 * j]), 3 * (1) );
      delay(t); pusto();
    }

  }
  // эффект 2
  for (int n = 0; n < 6; n++) {
    for (int j = 1; j < (line_ + 1); j++) {
      for (int i = 1; i <= j; i++) {
        WS2812bOut_P(dataPin_1, &(data_1[3 * n]), 3 * (1) );
      }
      delay(t);
    }
  }
  //  эффект 3
  pusto();
  int w = 0; int n = 0;
  while (w < 12) {
    n = random(0, 6);
    for (int i = 1; i < (line_ + 1); i++) {
      WS2812bOut_P(dataPin_1, &(data_1[3 * n]), 3 * (1) );
    }
    delay(20 * t);
    w++;
  }
  //  эффект 4
  w = 0;
  while (w < 6) {
    for (int i = line_; i >= 1; i--) {
      WS2812bOut_P(dataPin_1, &(data_2[3 * 0]), 3 * i); //пусто
      WS2812bOut_P(dataPin_1, &(data_1[3 * 0]), 3 * (6) );
      WS2812bOut_P(dataPin_1, &(data_1[3 * 0]), 3 * (6) );
      WS2812bOut_P(dataPin_1, &(data_1[3 * 0]), 3 * (6) );
      WS2812bOut_P(dataPin_1, &(data_1[3 * 0]), 3 * (6) );
      WS2812bOut_P(dataPin_1, &(data_1[3 * 0]), 3 * (6) );
      WS2812bOut_P(dataPin_1, &(data_1[3 * 0]), 3 * (6) );
      delay(1.5 * t);
    }
    for (int i = 1; i < (line_ + 1); i++) {
      WS2812bOut_P(dataPin_1, &(data_2[3 * 0]), 3 * i); //пусто
      WS2812bOut_P(dataPin_1, &(data_1[3 * 0]), 3 * (6) );
      WS2812bOut_P(dataPin_1, &(data_1[3 * 0]), 3 * (6) );
      WS2812bOut_P(dataPin_1, &(data_1[3 * 0]), 3 * (6) );
      WS2812bOut_P(dataPin_1, &(data_1[3 * 0]), 3 * (6) );
      WS2812bOut_P(dataPin_1, &(data_1[3 * 0]), 3 * (6) );
      WS2812bOut_P(dataPin_1, &(data_1[3 * 0]), 3 * (6) );
      delay(t);
    }
    w++;
  }
}
//////////////////////////////////////////////////////
#define arraySize(_array) ( sizeof(_array) / sizeof(*_array) )
// Push bits to stripe
static void WS2812bOut_P(const uint8_t _dataPin, const uint8_t* _data, uint16_t _dataSize)  {
  volatile uint8_t hi, lo, next, currentBit = 0x08, *port, *ptrData = (volatile uint8_t*)(_data );
  uint8_t pinMask;

  port    = portOutputRegister(digitalPinToPort(_dataPin));
  pinMask = digitalPinToBitMask(_dataPin);

  hi = *port |  pinMask;
  lo = *port & ~pinMask;
  next = lo;
  /*
    // WS2812 RESET command
    digitalWrite(dataPin_1, LOW);
    delayMicroseconds(50);
  */
  // Some kind of magic here, thanx to Adafruit Neopixel source
  noInterrupts();
  asm volatile (
    "lpm  r0,  Z+"              "\n\t"
    "head20P:"                  "\n\t"
    "st   %a[port],  %[hi]"     "\n\t"
    "sbrc r0,  7"               "\n\t"
    "mov  %[next], %[hi]"       "\n\t"
    "dec  %[bit]"               "\n\t"
    "st   %a[port],  %[next]"   "\n\t"
    "mov  %[next] ,  %[lo]"     "\n\t"
    "breq nextbyte20P"          "\n\t"
    "rol  r0"                   "\n\t"
    "rjmp .+0"                  "\n\t"
    "nop"                       "\n\t"
    "st   %a[port],  %[lo]"     "\n\t"
    "nop"                       "\n\t"
    "rjmp .+0"                  "\n\t"
    "rjmp head20P"              "\n\t"
    "nextbyte20P:"              "\n\t"
    "ldi  %[bit]  ,  8"         "\n\t"
    "lpm  r0,  Z+"              "\n\t"
    "st   %a[port], %[lo]"      "\n\t"
    "sbiw %[count], 1"          "\n\t"
    "brne head20P"              "\n\t"
    : [port]  "+e" (port),
    [bit]     "+d" (currentBit),
    [next]    "+r" (next),
    [count]   "+w" (_dataSize)
    :         "z" (ptrData),
    [hi]      "r" (hi),
    [lo]      "r" (lo)
  );
  interrupts();
}

/////////////////////////////////////
void pusto() {
  WS2812bOut_P(dataPin_1, &(data_2[0]), 3 * (line_) ); //
  delayMicroseconds(dt);
}
/////////////////////////////////////

 

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

lilik https://wokwi.com/projects/328014892704465492 самый быстрый вывод. Поменять ОЗУ на PROGMEM и всё.

sadman41
Offline
Зарегистрирован: 19.10.2016

Просто добавить PROGMEM к массиву, не меняя кода?

lilik
Offline
Зарегистрирован: 19.10.2017

:)

Попробовал код. Рабочий. Нифига не ясно что куда в этой функции, но при 680 пикселях честно пишет что "алес на 100%"

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

sadman41 пишет:
Просто добавить PROGMEM к массиву, не меняя кода?

Этого не достаточно конечно. Без LPM не заработает ...

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

lilik пишет:

:)

Попробовал код. Рабочий. Нифига не ясно что куда в этой функции, но при 680 пикселях честно пишет что "алес на 100%"

Так это же для массива в ОЗУ. Под PROGMEM надо подшаманить чутка...

lilik
Offline
Зарегистрирован: 19.10.2017

Komandir пишет:

lilik пишет:

:)

Попробовал код. Рабочий. Нифига не ясно что куда в этой функции, но при 680 пикселях честно пишет что "алес на 100%"

Так это же для массива в ОЗУ. Под PROGMEM надо подшаманить чутка...

А смысл? Sadman41 уже сделал функцию для работы непосредственно с "динамичными и статичными массивами".

Вопрос был в частном случае применения с исключением и самих массивов в работе с лентой, т.е.

насколько работоспособна конструкция, включающая всю цепочку светодиодов:

fun(pin,R,0,0);
fun(pin,0,G,0);
fun(pin,0,0,B);
fun(pin,R,0,0);
fun(pin,0,G,0);
fun(pin,0,0,B);
delay(1000);

а не первый в режиме мигания:

fun(pin,R,0,0);
delay(1000);
fun(pin,0,G,0);
delay(1000);
fun(pin,0,0,B);
delay(1000);
fun(pin,R,0,0);
delay(1000);
fun(pin,0,G,0);
delay(1000);
fun(pin,0,0,B);
delay(1000);

Вот о чём я просил. Т.е. работает код как надо у кого-то ещё кроме меня или нет.

/////////////////////////////////////
/// тест ws2812b
////////////////////////////////////
#define line_ 33
uint8_t dataPin_1 = 6;
int dt = 75; //
int t = 30; //пауза
const byte k = 7; //яркость

/// GRB
const byte data_1[]PROGMEM  = {0, k, 0,  k, 0, 0,  0, 0, k,  k, k, 0,  0, k, k,  k, 0, k, k/3,2*k,0}; // палитра цветов
const byte data_2[line_ * 3]PROGMEM = {}; // пусто-сброс

void setup() {
  pinMode(dataPin_1, OUTPUT);
  pusto();
}

void loop() {
  // эффект 1
  for (int j = 0; j < 6; j++) {
    for (int i = 1; i < (line_ + 1); i++) {
      WS2812bOut_P(dataPin_1, &(data_2[3 * 0]), 3 * i); //пусто
      WS2812bOut_P(dataPin_1, &(data_1[3 * j]), 3 * (1) ); //перебор цветов
      WS2812bOut_P(dataPin_1, &(data_1[3 * j]), 3 * (1) );
      WS2812bOut_P(dataPin_1, &(data_1[3 * j]), 3 * (1) );
      WS2812bOut_P(dataPin_1, &(data_1[3 * j]), 3 * (1) );
      WS2812bOut_P(dataPin_1, &(data_1[3 * j]), 3 * (1) );
      delay(t); pusto();
    }

  }
  // эффект 2
  for (int n = 0; n < 6; n++) {
    for (int j = 1; j < (line_ + 1); j++) {
      for (int i = 1; i <= j; i++) {
        WS2812bOut_P(dataPin_1, &(data_1[3 * n]), 3 * (1) );
      }
      delay(t);
    }
  }
  //  эффект 3
  pusto();
  int w = 0; int n = 0;
  while (w < 12) {
    n = random(0, 6);
    for (int i = 1; i < (line_ + 1); i++) {
      WS2812bOut_P(dataPin_1, &(data_1[3 * n]), 3 * (1) );
    }
    delay(20 * t);
    w++;
  }
  //  эффект 4
  w = 0;
  while (w < 4) {
    for (int i = line_; i >= 1; i--) {
      WS2812bOut_P(dataPin_1, &(data_2[3 * 0]), 3 * i); //пусто
      WS2812bOut_P(dataPin_1, &(data_1[3 * 0]), 3 * (6) );
      WS2812bOut_P(dataPin_1, &(data_1[3 * 0]), 3 * (6) );
      WS2812bOut_P(dataPin_1, &(data_1[3 * 0]), 3 * (6) );
      WS2812bOut_P(dataPin_1, &(data_1[3 * 0]), 3 * (6) );
      WS2812bOut_P(dataPin_1, &(data_1[3 * 0]), 3 * (6) );
      WS2812bOut_P(dataPin_1, &(data_1[3 * 0]), 3 * (6) );
      delay(2.5 * t);
    }
    for (int i = 1; i < (line_ + 1); i++) {
      WS2812bOut_P(dataPin_1, &(data_2[3 * 0]), 3 * i); //пусто
      WS2812bOut_P(dataPin_1, &(data_1[3 * 0]), 3 * (6) );
      WS2812bOut_P(dataPin_1, &(data_1[3 * 0]), 3 * (6) );
      WS2812bOut_P(dataPin_1, &(data_1[3 * 0]), 3 * (6) );
      WS2812bOut_P(dataPin_1, &(data_1[3 * 0]), 3 * (6) );
      WS2812bOut_P(dataPin_1, &(data_1[3 * 0]), 3 * (6) );
      WS2812bOut_P(dataPin_1, &(data_1[3 * 0]), 3 * (6) );
      delay(t);
    }
    w++;
  }
 //  эффект 5
 w = 0;
  while (w < 6) {
for (int j = 0; j < 1.5*(line_ + 1); j++) {
  for (int i = 0; i <=j; i++) {
  WS2812bOut_P(dataPin_1, &(data_1[3 * 2]), 3 * (1) );
  }
  for (int i = 0; i <=j; i++) {
  WS2812bOut_P(dataPin_1, &(data_1[3 * 6]), 3 * (1) );
  }
  for (int i = 0; i <=j; i++) {
  WS2812bOut_P(dataPin_1, &(data_1[3 * 2]), 3 * (1) );
  }
   delay(t);
 }
 w++;
 }    
}
//////////////////////////////////////////////////////
#define arraySize(_array) ( sizeof(_array) / sizeof(*_array) )
// Push bits to stripe
static void WS2812bOut_P(const uint8_t _dataPin, const uint8_t* _data, uint16_t _dataSize)  {
  volatile uint8_t hi, lo, next, currentBit = 0x08, *port, *ptrData = (volatile uint8_t*)(_data );
  uint8_t pinMask;

  port    = portOutputRegister(digitalPinToPort(_dataPin));
  pinMask = digitalPinToBitMask(_dataPin);

  hi = *port |  pinMask;
  lo = *port & ~pinMask;
  next = lo;
  /*
    // WS2812 RESET command
    digitalWrite(_dataPin, LOW);
    delayMicroseconds(50);
  */
  
  // Some kind of magic here, thanx to Adafruit Neopixel source
  noInterrupts();
  asm volatile (
    "lpm  r0,  Z+"              "\n\t"
    "head20P:"                  "\n\t"
    "st   %a[port],  %[hi]"     "\n\t"
    "sbrc r0,  7"               "\n\t"
    "mov  %[next], %[hi]"       "\n\t"
    "dec  %[bit]"               "\n\t"
    "st   %a[port],  %[next]"   "\n\t"
    "mov  %[next] ,  %[lo]"     "\n\t"
    "breq nextbyte20P"          "\n\t"
    "rol  r0"                   "\n\t"
    "rjmp .+0"                  "\n\t"
    "nop"                       "\n\t"
    "st   %a[port],  %[lo]"     "\n\t"
    "nop"                       "\n\t"
    "rjmp .+0"                  "\n\t"
    "rjmp head20P"              "\n\t"
    "nextbyte20P:"              "\n\t"
    "ldi  %[bit]  ,  8"         "\n\t"
    "lpm  r0,  Z+"              "\n\t"
    "st   %a[port], %[lo]"      "\n\t"
    "sbiw %[count], 1"          "\n\t"
    "brne head20P"              "\n\t"
    : [port]  "+e" (port),
    [bit]     "+d" (currentBit),
    [next]    "+r" (next),
    [count]   "+w" (_dataSize)
    :         "z" (ptrData),
    [hi]      "r" (hi),
    [lo]      "r" (lo)
  );
  interrupts();
 
}

/////////////////////////////////////
void pusto() {
  WS2812bOut_P(dataPin_1, &(data_2[0]), 3 * (line_) ); //
  delayMicroseconds(dt);
}
/////////////////////////////////////

 

lilik
Offline
Зарегистрирован: 19.10.2017

Вот это тест проще на восприятие:

/////////////////////////////////////
/// тест ws2812b
////////////////////////////////////
uint8_t dataPin = 6;
///RGB
 void setup() {}

void loop() {
  //мигалка палитра на 6 пикселей
WS2812bOut(dataPin,5,0,0);
WS2812bOut(dataPin,0,5,0);
WS2812bOut(dataPin,0,0,5);
WS2812bOut(dataPin,5,5,0);
WS2812bOut(dataPin,0,5,5);
WS2812bOut(dataPin,5,0,5);//самый удалённый от начала ленты пиксель
delay(200);
WS2812bOut(dataPin,0,0,0);
WS2812bOut(dataPin,0,0,0);
WS2812bOut(dataPin,0,0,0);
WS2812bOut(dataPin,0,0,0);
WS2812bOut(dataPin,0,0,0);
WS2812bOut(dataPin,0,0,0);//самый удалённый от начала ленты пиксель
delay(200);
}
//////////////////////////////////////////////////////
static void WS2812bOut(const uint8_t _dataPin,uint8_t R,uint8_t G,uint8_t B )  {
uint8_t _data[]={G,R,B}; uint16_t _dataSize = 3;
  volatile uint8_t hi, lo, next, currentByte, currentBit = 0x08, *port, *ptrData = _data;
  uint8_t pinMask;

  digitalWrite(_dataPin, LOW);
  pinMode(_dataPin, OUTPUT);

  port    = portOutputRegister(digitalPinToPort(_dataPin));
  pinMask = digitalPinToBitMask(_dataPin);

  currentByte = *ptrData++;


  hi = *port |  pinMask;
  lo = *port & ~pinMask;
  next = lo;

  noInterrupts();
 asm volatile (
     "head20:"                   "\n\t" // Clk  Pseudocode    (T =  0)
      "st   %a[port],  %[hi]"    "\n\t" // 2    PORT = hi     (T =  2)
      "sbrc %[byte],  7"         "\n\t" // 1-2  if(b & 128)
       "mov  %[next], %[hi]"     "\n\t" // 0-1   next = hi    (T =  4)
      "dec  %[bit]"              "\n\t" // 1    bit--         (T =  5)
      "st   %a[port],  %[next]"  "\n\t" // 2    PORT = next   (T =  7)
      "mov  %[next] ,  %[lo]"    "\n\t" // 1    next = lo     (T =  8)
      "breq nextbyte20"          "\n\t" // 1-2  if(bit == 0) (from dec above)
      "rol  %[byte]"             "\n\t" // 1    b <<= 1       (T = 10)
      "rjmp .+0"                 "\n\t" // 2    nop nop       (T = 12)
      "nop"                      "\n\t" // 1    nop           (T = 13)
      "st   %a[port],  %[lo]"    "\n\t" // 2    PORT = lo     (T = 15)
      "nop"                      "\n\t" // 1    nop           (T = 16)
      "rjmp .+0"                 "\n\t" // 2    nop nop       (T = 18)
      "rjmp head20"              "\n\t" // 2    -> head20 (next bit out)
     "nextbyte20:"               "\n\t" //                    (T = 10)
      "ldi  %[bit]  ,  8"        "\n\t" // 1    bit = 8       (T = 11)
      "ld   %[byte] ,  %a[ptr]+" "\n\t" // 2    b = *ptr++    (T = 13)
      "st   %a[port], %[lo]"     "\n\t" // 2    PORT = lo     (T = 15)
      "nop"                      "\n\t" // 1    nop           (T = 16)
      "sbiw %[count], 1"         "\n\t" // 2    i--           (T = 18)
       "brne head20"             "\n"   // 2    if(i != 0) -> (next byte)
    : [port]  "+e" (port),
    [byte]  "+r" (currentByte),
    [bit]   "+r" (currentBit),
    [next]  "+r" (next),
    [count] "+w" (_dataSize)
    : [ptr]    "e" (ptrData),
    [hi]     "r" (hi),
    [lo]     "r" (lo)
  );

  interrupts();
}
//////////////////////////////////////////////////////

 

sadman41
Offline
Зарегистрирован: 19.10.2016

Друзья, я поместил сюда свой пост только потому, что он затрагивает PGM и это соответствует теме. 

А спорить как лучше и правильней выкидывать байты в страйп можно бесконечно...

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

lilik вы посмотрите какой код порождается при вызове функций с таким количеством параметров !

lilik
Offline
Зарегистрирован: 19.10.2017

Не знаю, скорее надо привыкнуть к манере иной написания. Пару дней назад, когда задумался над этим написал для сравнения два скетча на один эффект - с библиотекой и без :)

В моём исполнении они мало отличаются.

/////////////////////////////////////
/// тест ws2812b 
////////////////////////////////////
#define line_ 33
uint8_t dataPin_1 = 6;
int dt=75;//
int t=400;//пауза
const byte k=7;//яркость
long Y=0;//
int n=0;//

/// GRB
const byte data_1[]PROGMEM  = {0,k,0, k,0,0, 0,0,k, k,k,0, 0,k,k, k,0,k  }; // палитра цветов
const byte data_2[line_*3]PROGMEM = {};// пусто-сброс   

void setup() {
 pinMode(dataPin_1, OUTPUT);
 pusto();
 }

void loop() {
	// эффект 1
 for(int i=1;i<(line_+1);i++){
  WS2812bOut_P(dataPin_1, &(data_1[3*0]),3*(1) );//красный
 }
 delay_(t); pusto();
  for(int i=1;i<(line_+1)/1.2;i++){
  WS2812bOut_P(dataPin_1, &(data_1[3*1]),3*(1) );//зелёный
 }
 delay_(t); pusto();
 for(int i=1;i<(line_+1)/1.5;i++){
  WS2812bOut_P(dataPin_1, &(data_1[3*2]),3*(1) );//синий
 }
 delay_(t); pusto();
  for(int i=1;i<(line_+1)/2;i++){
  WS2812bOut_P(dataPin_1, &(data_1[3*3]),3*(1) );//жёлтый
 }
 delay_(t); pusto();  
 for(int i=1;i<(line_+1)/3;i++){
  WS2812bOut_P(dataPin_1,&(data_1[3*4]),3*(1) );//сиреневый
 }
 delay_(t); pusto();
  for(int i=1;i<(line_+1)/5;i++){
  WS2812bOut_P(dataPin_1, &(data_1[3*5]),3*(1) );//голубой
 }
 delay_(t);pusto();  
 }
//////////////////////////////////////////////////////
#define arraySize(_array) ( sizeof(_array) / sizeof(*_array) )
// Push bits to stripe 
static void WS2812bOut_P(const uint8_t _dataPin, const uint8_t* _data, uint16_t _dataSize)  {
  volatile uint8_t hi, lo, next, currentBit = 0x08, *port, *ptrData = (volatile uint8_t*)(_data );
  uint8_t pinMask;

  port    = portOutputRegister(digitalPinToPort(_dataPin));
  pinMask = digitalPinToBitMask(_dataPin);

  hi = *port |  pinMask;
  lo = *port & ~pinMask;
  next = lo;
  /*
    // WS2812 RESET command
    digitalWrite(dataPin, LOW);
    delayMicroseconds(50);
  */
  // Some kind of magic here, thanx to Adafruit Neopixel source
  noInterrupts();
  asm volatile (
    "lpm  r0,  Z+"              "\n\t"
    "head20P:"                  "\n\t"
    "st   %a[port],  %[hi]"     "\n\t"
    "sbrc r0,  7"               "\n\t"
    "mov  %[next], %[hi]"       "\n\t"
    "dec  %[bit]"               "\n\t"
    "st   %a[port],  %[next]"   "\n\t"
    "mov  %[next] ,  %[lo]"     "\n\t"
    "breq nextbyte20P"          "\n\t"
    "rol  r0"                   "\n\t"
    "rjmp .+0"                  "\n\t"
    "nop"                       "\n\t"
    "st   %a[port],  %[lo]"     "\n\t"
    "nop"                       "\n\t"
    "rjmp .+0"                  "\n\t"
    "rjmp head20P"              "\n\t"
    "nextbyte20P:"              "\n\t"
    "ldi  %[bit]  ,  8"         "\n\t"
    "lpm  r0,  Z+"              "\n\t"
    "st   %a[port], %[lo]"      "\n\t"
    "sbiw %[count], 1"          "\n\t"
    "brne head20P"              "\n\t"  
    : [port]  "+e" (port),
    [bit]     "+d" (currentBit),
    [next]    "+r" (next),
    [count]   "+w" (_dataSize)
    :         "z" (ptrData),
    [hi]      "r" (hi),
    [lo]      "r" (lo)
  );
  interrupts();
}
//////////////////////////////////////////////////////
void delay_(int T){
  Y=millis(); 
 while(millis()-Y<T){
  }
// n++;if(n>100){n=0;t=t+10;if(t>40){t=10;}} 
}
/////////////////////////////////////
void pusto(){
 WS2812bOut_P(dataPin_1, &(data_2[0]),3*(line_) );//
 delayMicroseconds(dt);  
}
/////////////////////////////////////
#include "Adafruit_NeoPixel.h"
#define LED_COUNT1 33
#define LED_PIN1 6
int k=5;//
int t=400;//

Adafruit_NeoPixel strip1 = Adafruit_NeoPixel(LED_COUNT1, LED_PIN1, NEO_GRB + NEO_KHZ800);// Создаем переменную strip для управления нашей лентой.
void setup () {
 strip1.begin();
 pusto();
}
void loop () {
 // эффект 1
 for(int i=0;i<(LED_COUNT1);i++){
 strip1.setPixelColor(i, k, 0, 0); // ;//красный
 }
  strip1.show(); delay(t); pusto();
  
  for(int i=0;i<(LED_COUNT1)/1.2;i++){
strip1.setPixelColor(i, 0, k, 0); //зелёный
 }
 strip1.show(); delay(t); pusto();
 
 for(int i=0;i<(LED_COUNT1)/1.5;i++){
  strip1.setPixelColor(i, 0, 0, k);//синий
 }
 strip1.show(); delay(t); pusto();
 
  for(int i=0;i<(LED_COUNT1)/2;i++){
  strip1.setPixelColor(i, k, k, 0);//жёлтый
 }
 strip1.show(); delay(t); pusto();
   
 for(int i=0;i<(LED_COUNT1)/3;i++){
 strip1.setPixelColor(i, k, 0, k);//сиреневый
 }
  strip1.show();delay(t); pusto();
  
  for(int i=0;i<(LED_COUNT1)/5;i++){
  strip1.setPixelColor(i, 0, k, k);//голубой
 }
 strip1.show(); delay(t); pusto();   
}
//////////////////////////////////
void pusto(){
////////// выключение пикселей 
  for (int i = 0; i < LED_COUNT1; i++) {
    strip1.setPixelColor(i, 0, 0, 0); //
  }
  strip1.show();  
}
/////////////////////////////////

 

lilik
Offline
Зарегистрирован: 19.10.2017
/////////////////////////////////////
/// примеры для ws2812b
////////////////////////////////////
#define line_ 33 //число пикселей в ленте
uint8_t dataPin = 6;// вывод для подключения
int R=0;int G=0;int B=0;//
int t=75;//

///RGB
void setup() {
}
void loop() {
  for (int ti = 0; ti < line_; ti++) {
    for (int ni = 0; ni < line_; ni++) {
     cvet(ti,ni);// функция определения цвета пикселя в зависимости от его номера в ленте и момента времени (кадра анимации)
     WS2812bOut(dataPin, R, G, B);
  }
   delay(t);
  }
 }
///////////////////////////////////////
void cvet (int it,int in){
 if(it==in){R=0;G=10;B=0;}else{R=0;G=0;B=0;}//бегущий по ленте зелёный пиксель 
}
//////////////////////////////////////

:)

Спустя столько лет до меня стали доходить пророческие слова Логика из последнего сообщения темы:

https://arduino.ru/forum/programmirovanie/upravlenie-adresnoi-svetodiodn...

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

Да что там лента ... у меня SSD1306 без буфера в ОЗУ отображает информацию ...

lilik
Offline
Зарегистрирован: 19.10.2017

Komandir пишет:

Да что там лента ... у меня SSD1306 без буфера в ОЗУ отображает информацию ...

Я в прошлом году пробовал, дошло до рисования окружности, но слишком долго и затея была заброшена.

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

Не на одних окружностях мир держится ...

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Komandir пишет:

Да что там лента ... у меня SSD1306 без буфера в ОЗУ отображает информацию ...

Ну как бы не только у тебя.

Тебя еще на форуме не было, а библиотека с таким способом отображения уже была: http://arduino.ru/forum/proekty/asoled-kompaktnaya-biblioteka-dlya-oled-...

 
andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

и не лень вам "письками меряться", че там отображать то....при разрешении 128*64*1бит цветности вшивый килобайт данных выплюнуть в порт.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Komandir пишет:

Не на одних окружностях мир держится ...

это уже философский вопрос )))

lilik
Offline
Зарегистрирован: 19.10.2017

:)

Вообще тема безбуферной жизни весьма актуальна сегодня не только в лентах и экранчиках.

lilik
Offline
Зарегистрирован: 19.10.2017

/////////////////////////////////////
/// примеры для ws2812b
////////////////////////////////////
#define line_ 33 //число пикселей в ленте
uint8_t dataPin = 6;// вывод для подключения
int R=0;int G=0;int B=0;//
int t=100;//

///RGB
void setup() {
}
void loop() {
  for (int ti = 0; ti < line_; ti++) {
    for (int ni = 0; ni < line_; ni++) {
     cvet(ti,ni);// функция определения цвета пикселя в зависимости от его номера в ленте и момента времени (кадра анимации)
     WS2812bOut(dataPin, R, G, B);
  }
   delay(t);
  }
 }
///////////////////////////////////////
void cvet (int it,int in){
// if(it==in){R=0;G=10;B=0;}else{R=0;G=0;B=0;}//бегущий по ленте -> зелёный пиксель ->
int mnogo=6; R=5*((in+it%mnogo)%mnogo);G=5*((mnogo-1-(in+it%mnogo)%mnogo));B=0;// бегущая по ленте <-палитра от зелёного до красного (переход из 6 штук)<-
}
//////////////////////////////////////

Придумал обалденный эффект (одной строчкой всего задаётся). Переход палитры определяется переменной mnogo. Всё работает как задумано, НО! если брать значение 8,16 и т.д. выскакивает запись при компиляции - ошибка для платы ... Почему так для этих чисел?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

lilik пишет:
если брать значение 8,16 и т.д. выскакивает запись при компиляции - ошибка для платы ... Почему так для этих чисел?

Куда и как брать? Приведите код в котором "выскакивает" и в котором "не выскакивает".

lilik
Offline
Зарегистрирован: 19.10.2017

Не выскакивает и скетч работает:

/////////////////////////////////////
/// примеры для ws2812b
////////////////////////////////////
#define line_ 33 //число пикселей в ленте
uint8_t dataPin = 6;// вывод для подключения
int R=0;int G=0;int B=0;//
int t=100;//

///RGB
void setup() {
}
void loop() {
  for (int ti = 0; ti < line_; ti++) {
    for (int ni = 0; ni < line_; ni++) {
     cvet(ti,ni);// функция определения цвета пикселя в зависимости от его номера в ленте и момента времени (кадра анимации)
     WS2812bOut(dataPin, R, G, B);
  }
   delay(t);
  }
 }
///////////////////////////////////////
void cvet (int it,int in){
// if(it==in){R=0;G=10;B=0;}else{R=0;G=0;B=0;}//бегущий по ленте -> зелёный пиксель ->
int mnogo=6; R=5*((in+it%mnogo)%mnogo);G=5*((mnogo-1-(in+it%mnogo)%mnogo));B=0;// бегущая по ленте <-палитра от зелёного до красного (переход из 6 штук)<-
}
//////////////////////////////////////

 Выскакивает и всё тут:

/////////////////////////////////////
/// примеры для ws2812b
////////////////////////////////////
#define line_ 33 //число пикселей в ленте
uint8_t dataPin = 6;// вывод для подключения
int R=0;int G=0;int B=0;//
int t=100;//

///RGB
void setup() {
}
void loop() {
  for (int ti = 0; ti < line_; ti++) {
    for (int ni = 0; ni < line_; ni++) {
     cvet(ti,ni);// функция определения цвета пикселя в зависимости от его номера в ленте и момента времени (кадра анимации)
     WS2812bOut(dataPin, R, G, B);
  }
   delay(t);
  }
 }
///////////////////////////////////////
void cvet (int it,int in){
// if(it==in){R=0;G=10;B=0;}else{R=0;G=0;B=0;}//бегущий по ленте -> зелёный пиксель ->
int mnogo=8; R=5*((in+it%mnogo)%mnogo);G=5*((mnogo-1-(in+it%mnogo)%mnogo));B=0;// бегущая по ленте <-палитра от зелёного до красного (переход из 6 штук)<-
}
//////////////////////////////////////

 

b707
Offline
Зарегистрирован: 26.05.2017

красиво однако, но как это понять?

asm volatile (
    "lpm  r0,  Z+"              "\n\t"
    "head20P:"                  "\n\t"
    "st   %a[port],  %[hi]"     "\n\t"
    "sbrc r0,  7"               "\n\t"
    "mov  %[next], %[hi]"       "\n\t"
    "dec  %[bit]"               "\n\t"
    "st   %a[port],  %[next]"   "\n\t"
    "mov  %[next] ,  %[lo]"     "\n\t"
    "breq nextbyte20P"          "\n\t"
    "rol  r0"                   "\n\t"
    "rjmp .+0"                  "\n\t"
    "nop"                       "\n\t"
    "st   %a[port],  %[lo]"     "\n\t"
    "nop"                       "\n\t"
    "rjmp .+0"                  "\n\t"
    "rjmp head20P"              "\n\t"
    "nextbyte20P:"              "\n\t"
    "ldi  %[bit]  ,  8"         "\n\t"
    "lpm  r0,  Z+"              "\n\t"
    "st   %a[port], %[lo]"      "\n\t"
    "sbiw %[count], 1"          "\n\t"
    "brne head20P"              "\n\t"
    : [port]  "+e" (port),
    [bit]     "+d" (currentBit),
    [next]    "+r" (next),
    [count]   "+w" (_dataSize)
    :         "z" (ptrData),
    [hi]      "r" (hi),
    [lo]      "r" (lo)
  );
  interrupts();
 
}

я тут с полгода назад пытался асм освоить - не так-то это просто. В тестовом скетче работает, а как вставляешь в реальную программу - фиг вам....

 

PS это я так, не обращайте внимания...

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

lilik пишет:

Не выскакивает и скетч работает:

Скетч неполный (в обоих случаях). Функция  WS2812bOut не определена.

Если же её вызов закомментировать, то у меня ничего "не выскакивает" ни в одном, ни в другом.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

b707 пишет:

красиво однако, но как это понять?

Ну, понять-то можно, но не люблю я этот inline-assembler, если надо больше одной строки написать. Предпочитаю отдельный файл и там на чистом ассемблере нужные функции, а из С/С++ их вызывать. Можно использовать макросы, структуры и прочие ассемблерные вкусняшки, которые в inline недоступны.

lilik
Offline
Зарегистрирован: 19.10.2017

ЕвгенийП пишет:

lilik пишет:

Не выскакивает и скетч работает:

Скетч неполный (в обоих случаях). Функция  WS2812bOut не определена.

Если же её вызов закомментировать, то у меня ничего "не выскакивает" ни в одном, ни в другом.

Забыл в угаре экспериментов, функция отдельным ino приложена в папку основного скетча. Она видимо на всё и влияет.

/////////////////////////////////////////////////////////////////////////////////////////////////
static void WS2812bOut(const uint8_t _dataPin, uint8_t R, uint8_t G, uint8_t B )  {
  uint8_t _data[] = {G, R, B}; uint16_t _dataSize = 3;
  volatile uint8_t hi, lo, next, currentByte, currentBit = 0x08, *port, *ptrData = _data;
  uint8_t pinMask;

  digitalWrite(_dataPin, LOW);
  pinMode(_dataPin, OUTPUT);

  port    = portOutputRegister(digitalPinToPort(_dataPin));
  pinMask = digitalPinToBitMask(_dataPin);

  currentByte = *ptrData++;


  hi = *port |  pinMask;
  lo = *port & ~pinMask;
  next = lo;

  noInterrupts();
  asm volatile (
    "head20:"                   "\n\t" // Clk  Pseudocode    (T =  0)
    "st   %a[port],  %[hi]"    "\n\t" // 2    PORT = hi     (T =  2)
    "sbrc %[byte],  7"         "\n\t" // 1-2  if(b & 128)
    "mov  %[next], %[hi]"     "\n\t" // 0-1   next = hi    (T =  4)
    "dec  %[bit]"              "\n\t" // 1    bit--         (T =  5)
    "st   %a[port],  %[next]"  "\n\t" // 2    PORT = next   (T =  7)
    "mov  %[next] ,  %[lo]"    "\n\t" // 1    next = lo     (T =  8)
    "breq nextbyte20"          "\n\t" // 1-2  if(bit == 0) (from dec above)
    "rol  %[byte]"             "\n\t" // 1    b <<= 1       (T = 10)
    "rjmp .+0"                 "\n\t" // 2    nop nop       (T = 12)
    "nop"                      "\n\t" // 1    nop           (T = 13)
    "st   %a[port],  %[lo]"    "\n\t" // 2    PORT = lo     (T = 15)
    "nop"                      "\n\t" // 1    nop           (T = 16)
    "rjmp .+0"                 "\n\t" // 2    nop nop       (T = 18)
    "rjmp head20"              "\n\t" // 2    -> head20 (next bit out)
    "nextbyte20:"               "\n\t" //                    (T = 10)
    "ldi  %[bit]  ,  8"        "\n\t" // 1    bit = 8       (T = 11)
    "ld   %[byte] ,  %a[ptr]+" "\n\t" // 2    b = *ptr++    (T = 13)
    "st   %a[port], %[lo]"     "\n\t" // 2    PORT = lo     (T = 15)
    "nop"                      "\n\t" // 1    nop           (T = 16)
    "sbiw %[count], 1"         "\n\t" // 2    i--           (T = 18)
    "brne head20"             "\n"   // 2    if(i != 0) -> (next byte)
    : [port]  "+e" (port),
    [byte]  "+r" (currentByte),
    [bit]   "+r" (currentBit),
    [next]  "+r" (next),
    [count] "+w" (_dataSize)
    : [ptr]    "e" (ptrData),
    [hi]     "r" (hi),
    [lo]     "r" (lo)
  );
  interrupts();
}
///////////////////////////////////////////////////////

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Так лучше. Теперь функция определена.

У меня оба Ваши примера нормально компилируются. Без всяких сообщений

lilik
Offline
Зарегистрирован: 19.10.2017

У меня Arduino ide 1.8.2

Наблюдается ещё более интересное:

if(in<=it){R=15;G=2;B=0;}else{R=0;G=0;B=15;}//

Вот такая строка-условие эффекта пройдёт, а ниже уже нет

if(in<=it){R=15;G=2;B=0;}else{R=0;G=0;B=20;}//

Их отличие: в верхней для RGB комбинация из 3 чисел, в нижней из 4.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

andycat пишет:

и не лень вам "письками меряться", че там отображать то....при разрешении 128*64*1бит цветности вшивый килобайт данных выплюнуть в порт.

Вообще-то отказ от буфера обычно вызван не соображениями скорости (хотя i2c на стандартных 100 кГц - тоже далеко не 60 fps), а соображениями экономии памяти.

lilik
Offline
Зарегистрирован: 19.10.2017

ЕвгенийП пишет:

Так лучше. Теперь функция определена.

У меня оба Ваши примера нормально компилируются. Без всяких сообщений

Пробовал разные варианты переборов эффектов и при таком все ошибки исчезли почему то:

/////////////////////////////////////
/// примеры для ws2812b
////////////////////////////////////
#define line_ 33 //число пикселей в ленте
uint8_t dataPin = 6;// вывод для подключения
byte R=0; byte G=0; byte B=0;//составляющие цвета пикселя
int t=75;// пауза между кадрами
byte effekt=1;// номер эффекта

///RGB
void setup() {
}
void loop() {
  effekt=random(1,5);//псевдослучайный выбор эффекта
 /// 
  for (int ti = 0; ti < line_; ti++) {//перебор номеров кадров в ленте
    for (int ni = 0; ni < line_; ni++) {//перебор номеров пикселей в ленте
     cvet(ti,ni);// функция определения цвета пикселя в зависимости от его номера в ленте и момента времени (кадра анимации)   
     WS2812bOut(dataPin, R, G, B);//функция вывода данных цвета для текущего номера пикселя
    }
   delay(t);
  }
 ///
 }
///////////////////////////////////////
void cvet (int it,int in){
 switch (effekt) {
    case 1:
      if(in==it){R=0;G=14;B=2;}else{R=7;G=1;B=0;}//бегущий по оранжевой ленте -> цвета бирюзового пиксель ->
      break;
    case 2:
     { byte mnogo=8; R=5*((in+it%mnogo)%mnogo);G=5*((mnogo-1-(in+it%mnogo)%mnogo));B=0;}// бегущая по ленте <-палитра от зелёного до красного (переход из 8 штук)<-
      break;
    case 3:
      if(in<=it){R=5;G=0;B=10;}else{R=0;G=10;B=0;}// ->полоса фиолетового цвета набегает на полосу зелёного ->
      break;
     case 4:
      if(in%(it+1)==0){R=15;G=15;B=10;}else{R=7;G=1;B=1;}// -> выстрел белыми пикселями с их взаиморазлётом -> на розовом фоне 
      break;
     default:
       R=0;G=0;B=0;//выключаем пиксели если не выбран эффект
  } 
}
//////////////////////////////////////

/////////////////////////////////////////////////////////////////////////////////////////////////
static void WS2812bOut(const uint8_t _dataPin, uint8_t R, uint8_t G, uint8_t B )  {
  uint8_t _data[] = {G, R, B}; uint16_t _dataSize = 3;
  volatile uint8_t hi, lo, next, currentByte, currentBit = 0x08, *port, *ptrData = _data;
  uint8_t pinMask;

  digitalWrite(_dataPin, LOW);
  pinMode(_dataPin, OUTPUT);

  port    = portOutputRegister(digitalPinToPort(_dataPin));
  pinMask = digitalPinToBitMask(_dataPin);

  currentByte = *ptrData++;


  hi = *port |  pinMask;
  lo = *port & ~pinMask;
  next = lo;

  noInterrupts();
  asm volatile (
    "head20:"                   "\n\t" // Clk  Pseudocode    (T =  0)
    "st   %a[port],  %[hi]"    "\n\t" // 2    PORT = hi     (T =  2)
    "sbrc %[byte],  7"         "\n\t" // 1-2  if(b & 128)
    "mov  %[next], %[hi]"     "\n\t" // 0-1   next = hi    (T =  4)
    "dec  %[bit]"              "\n\t" // 1    bit--         (T =  5)
    "st   %a[port],  %[next]"  "\n\t" // 2    PORT = next   (T =  7)
    "mov  %[next] ,  %[lo]"    "\n\t" // 1    next = lo     (T =  8)
    "breq nextbyte20"          "\n\t" // 1-2  if(bit == 0) (from dec above)
    "rol  %[byte]"             "\n\t" // 1    b <<= 1       (T = 10)
    "rjmp .+0"                 "\n\t" // 2    nop nop       (T = 12)
    "nop"                      "\n\t" // 1    nop           (T = 13)
    "st   %a[port],  %[lo]"    "\n\t" // 2    PORT = lo     (T = 15)
    "nop"                      "\n\t" // 1    nop           (T = 16)
    "rjmp .+0"                 "\n\t" // 2    nop nop       (T = 18)
    "rjmp head20"              "\n\t" // 2    -> head20 (next bit out)
    "nextbyte20:"               "\n\t" //                    (T = 10)
    "ldi  %[bit]  ,  8"        "\n\t" // 1    bit = 8       (T = 11)
    "ld   %[byte] ,  %a[ptr]+" "\n\t" // 2    b = *ptr++    (T = 13)
    "st   %a[port], %[lo]"     "\n\t" // 2    PORT = lo     (T = 15)
    "nop"                      "\n\t" // 1    nop           (T = 16)
    "sbiw %[count], 1"         "\n\t" // 2    i--           (T = 18)
    "brne head20"             "\n"   // 2    if(i != 0) -> (next byte)
    : [port]  "+e" (port),
    [byte]  "+r" (currentByte),
    [bit]   "+r" (currentBit),
    [next]  "+r" (next),
    [count] "+w" (_dataSize)
    : [ptr]    "e" (ptrData),
    [hi]     "r" (hi),
    [lo]     "r" (lo)
  );
  interrupts();
}
///////////////////////////////////////////////////////

 

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Не иначе как благодать снизошла...

lilik
Offline
Зарегистрирован: 19.10.2017

:)

Снизошла и ушла.

Вот красивый вариант мигалки, но стоит закоментить строку с рандомным выбором номера эффекта и выскакивает ошибка.

/////////////////////////////////////
/// примеры для ws2812b
////////////////////////////////////
#define line_ 33 //число пикселей в ленте
uint8_t dataPin = 6;// вывод для подключения
byte R=0; byte G=0; byte B=0;//составляющие цвета пикселя
int t=75;// пауза между кадрами
byte effekt=1;// номер эффекта

///RGB
void setup() {
}
void loop() {
  effekt=random(1,11);//псевдослучайный выбор эффекта
 /// 
  for (int ti = 0; ti < line_; ti++) {//перебор номеров кадров в ленте
    for (int ni = 0; ni < line_; ni++) {//перебор номеров пикселей в ленте
     cvet(ti,ni);// функция определения цвета пикселя в зависимости от его номера в ленте и момента времени (кадра анимации)   
     WS2812bOut(dataPin, R, G, B);//функция вывода данных цвета для текущего номера пикселя
    }
   delay(t);
  }
 ///
 }
///////////////////////////////////////
void cvet (int it,int in){
 switch (effekt) {
    case 1:
     if(in==it){R=0;G=14;B=2;}else{R=7;G=1;B=0;}//бегущий по оранжевой ленте -> цвета бирюзового пиксель ->
      break;
    case 2:
     { byte mnogo=9; R=5*((in+it%mnogo)%mnogo);G=5*((mnogo-1-(in+it%mnogo)%mnogo));B=0;}// бегущая по ленте <-палитра от зелёного до красного (переход из 9 штук)<-
      break;
    case 3:
      if(in<=it){R=5;G=0;B=10;}else{R=0;G=10;B=0;}// ->полоса фиолетового цвета набегает на полосу зелёного ->
      break;
     case 4:
      if(in%(it+1)==0){R=15;G=15;B=10;}else{R=7;G=1;B=1;}// -> выстрел белыми пикселями с их взаиморазлётом -> на розовом фоне 
      break;
      case 5:
     if(in==line_-it||in+1==line_-it||in+2==line_-it||in+3==line_-it||in+4==line_-it){R=15;G=3;B=0;}else{R=0;G=0;B=7;}//бегущий по синей ленте -> цвета оранжевого 5 пикселей ->
      break;
    case 6:
     { byte mnogo=10; R=5*((in+it%mnogo)%mnogo);G=0;B=5*((mnogo-1-(in+it%mnogo)%mnogo));}// бегущая по ленте <-палитра от синего до красного (переход из 10 штук)<-
      break;
    case 7:
      if(in<=line_-it){R=10;G=10;B=0;}else{R=0;G=7;B=7;}// <-полоса голубого цвета набегает на полосу жёлтого <-
      break;
     case 8:
      if(in%(it+1)==0){R=15;G=15;B=10;}else{R=0;G=2;B=2;}// -> выстрел белыми пикселями с их взаиморазлётом -> на голубом фоне 
      break;
    case 9:
     { byte mnogo=32; R=3;G=1*(mnogo-1-(it%mnogo));B=1*((it%mnogo));}// плавный переход цвета ленты от "зеленоватого к синеватому"
      break;  
    case 10:
     { byte mnogo=32; R=1*(mnogo-1-(it%mnogo));G=1;B=1*((it%mnogo));}// плавный переход цвета ленты от "красноватого к синеватому"
      break;   
     default:
       R=0;G=0;B=0;//выключаем пиксели если не выбран эффект
  } 
}
//////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////
static void WS2812bOut(const uint8_t _dataPin, uint8_t R, uint8_t G, uint8_t B )  {
  uint8_t _data[] = {G, R, B}; uint16_t _dataSize = 3;
  volatile uint8_t hi, lo, next, currentByte, currentBit = 0x08, *port, *ptrData = _data;
  uint8_t pinMask;

  digitalWrite(_dataPin, LOW);
  pinMode(_dataPin, OUTPUT);

  port    = portOutputRegister(digitalPinToPort(_dataPin));
  pinMask = digitalPinToBitMask(_dataPin);

  currentByte = *ptrData++;


  hi = *port |  pinMask;
  lo = *port & ~pinMask;
  next = lo;

  noInterrupts();
  asm volatile (
    "head20:"                   "\n\t" // Clk  Pseudocode    (T =  0)
    "st   %a[port],  %[hi]"    "\n\t" // 2    PORT = hi     (T =  2)
    "sbrc %[byte],  7"         "\n\t" // 1-2  if(b & 128)
    "mov  %[next], %[hi]"     "\n\t" // 0-1   next = hi    (T =  4)
    "dec  %[bit]"              "\n\t" // 1    bit--         (T =  5)
    "st   %a[port],  %[next]"  "\n\t" // 2    PORT = next   (T =  7)
    "mov  %[next] ,  %[lo]"    "\n\t" // 1    next = lo     (T =  8)
    "breq nextbyte20"          "\n\t" // 1-2  if(bit == 0) (from dec above)
    "rol  %[byte]"             "\n\t" // 1    b <<= 1       (T = 10)
    "rjmp .+0"                 "\n\t" // 2    nop nop       (T = 12)
    "nop"                      "\n\t" // 1    nop           (T = 13)
    "st   %a[port],  %[lo]"    "\n\t" // 2    PORT = lo     (T = 15)
    "nop"                      "\n\t" // 1    nop           (T = 16)
    "rjmp .+0"                 "\n\t" // 2    nop nop       (T = 18)
    "rjmp head20"              "\n\t" // 2    -> head20 (next bit out)
    "nextbyte20:"               "\n\t" //                    (T = 10)
    "ldi  %[bit]  ,  8"        "\n\t" // 1    bit = 8       (T = 11)
    "ld   %[byte] ,  %a[ptr]+" "\n\t" // 2    b = *ptr++    (T = 13)
    "st   %a[port], %[lo]"     "\n\t" // 2    PORT = lo     (T = 15)
    "nop"                      "\n\t" // 1    nop           (T = 16)
    "sbiw %[count], 1"         "\n\t" // 2    i--           (T = 18)
    "brne head20"             "\n"   // 2    if(i != 0) -> (next byte)
    : [port]  "+e" (port),
    [byte]  "+r" (currentByte),
    [bit]   "+r" (currentBit),
    [next]  "+r" (next),
    [count] "+w" (_dataSize)
    : [ptr]    "e" (ptrData),
    [hi]     "r" (hi),
    [lo]     "r" (lo)
  );
  interrupts();
}
///////////////////////////////////////////////////////

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

lilik пишет:
стоит закоментить строку с рандомным выбором номера эффекта и выскакивает ошибка.

Ну, Вы хоть номер строки говорите, чего ж Вы издеваетесь над людями то?

Если строка №14, то у меня проблемы нет. Комментирую и всё компилируется.

lilik
Offline
Зарегистрирован: 19.10.2017

Простите, я всё никак не могу понять в чём дело. Подробно о проблеме пишет так "иде":

C:\Users\MDI\AppData\Local\Temp\cc6t7Nyf.s: Assembler messages:

C:\Users\MDI\AppData\Local\Temp\cc6t7Nyf.s:611: Error: register number above 15 required

lto-wrapper: C:\Program Files (x86)\Arduino\hardware\tools\avr/bin/avr-gcc returned 1 exit status

c:/program files (x86)/arduino/hardware/tools/avr/bin/../lib/gcc/avr/4.9.2/../../../../avr/bin/ld.exe: error: lto-wrapper failed

collect2.exe: error: ld returned 1 exit status

exit status 1
Ошибка компиляции для платы Arduino Pro or Pro Mini.

 Просто выходит мало написать правильно скетч, его ещё надо написать в правильном "иде"? А какая у Вас версия? Я в нём год - полтора назад только одну строчку исправлял, касательно работы с HC-05.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Обновите IDE.