通过串行线路从栓系(主机)PC对Arduino/Atmel328进行机器编码

通过串行线路从栓系(主机)PC对Arduino/Atmel328进行机器编码,arduino,function-pointers,shared-memory,avr,atmel,Arduino,Function Pointers,Shared Memory,Avr,Atmel,我正在尝试为AVR Atmel 328芯片编写一个程序,该程序允许我通过串行线向芯片发送机器代码指令,在芯片上运行/执行这些指令,并通过读取芯片内存和通过串行线发回内容来查询结果。这就是这个想法的起源: 远程存储和远程获取指令似乎工作正常,但我无法使远程调用指令(XCALL()函数)工作。我采取的方法是通过将16位地址强制转换为函数指针,将其强制转换为子例程 下面是Arduino Nano上运行的代码(在Arduino IDE中编译并通过引导加载程序使用USB电缆上传) 如有任何见解,将不胜感激

我正在尝试为AVR Atmel 328芯片编写一个程序,该程序允许我通过串行线向芯片发送机器代码指令,在芯片上运行/执行这些指令,并通过读取芯片内存和通过串行线发回内容来查询结果。这就是这个想法的起源:

远程存储和远程获取指令似乎工作正常,但我无法使远程调用指令(
XCALL()
函数)工作。我采取的方法是通过将16位地址强制转换为函数指针,将其强制转换为子例程

下面是Arduino Nano上运行的代码(在Arduino IDE中编译并通过引导加载程序使用USB电缆上传)

如有任何见解,将不胜感激!(如果有帮助,我可以添加分离代码、远程指令等)

提前谢谢

// Remote serial development platform for machine coding ArduinoNano/ATmel328, AKE, Jun 9, 2020

// global variables
unsigned char byt;                  // command token from host
unsigned char mem[255];             // memory window under programmatic control
unsigned char dat;                  // data byte from host
unsigned char adr_lo;               // address from host, low byte first
unsigned char adr_hi;           
unsigned short adr;                 // combined 16-bit address
typedef void (*GeneralFunction)();  // template to call memory address (as a subroutine)

void setup() {
  Serial.begin(9600);              // Turn UART serial protocol ON for comms with host PC
  Serial.write(0xFF);              // magic number to verify transmission
  Serial.write(0xFE);
  Serial.write((int) mem);         // Informs you of the writeable address space available (LSB, MSB) for tethered memory access
  Serial.write((int) mem>>8);      
}

char get_byte(void) {
    while (!(Serial.available()>0)) { delay(50); }
    return Serial.read();
}
short get_adr(void) {
    adr_lo=get_byte();
    adr_hi=get_byte();
    return ( (short)adr_hi<<8 )   |   (short)adr_lo;
}
void xstore() {             // Instruction 1 = xstore(data,adr_lo,adr_hi).  Store byte from host at indicated address in target.
    dat=get_byte();
    adr=get_adr();
    *(char *)adr=dat;
}
void xfetch() {             //  Instruction 2 = xfetch(adr_lo,adr_hi).  Read byte from target memory and return to host.
        adr=get_adr();
        dat=*(char *)adr;
        Serial.write(dat);
}
void xcall() {              //  Instruction 3 = xcall(adr_lo,adr_hi).  Execute subroutine in target memory from indicated address.
                            //  WARNING!  User must have stored RET instruction to send control back to serial monitor.
        adr=get_adr();
        GeneralFunction fGf=adr;
        fGf();
}

void loop() {
    byt = get_byte();               // user specified instruction token (1,2,3)
    if(byt == 0x01 )      { xstore(); } 
    else if (byt == 0x02) { xfetch(); } 
    else if (byt == 0x3 ) { xcall(); } // else ignore any other serial inputs
}
//机器编码远程串行开发平台ArduinoNano/ATmel328,AKE,2020年6月9日
//全局变量
无符号字符byt;//来自主机的命令令牌
无符号字符mem[255];//程序控制下的内存窗口
无符号字符数据;//来自主机的数据字节
未签名字符adr_lo;//来自主机的地址,低字节优先
未签名字符adr_hi;
无符号短adr;//组合16位地址
typedef void(*GeneralFunction)(;//调用内存地址的模板(作为子例程)
无效设置(){
Serial.begin(9600);//为与主机PC的通信打开UART串行协议
Serial.write(0xFF);//验证传输的幻数
串行写入(0xFE);
Serial.write((int)mem);//通知您可用于连接内存访问的可写地址空间(LSB、MSB)
串行写入((int)mem>>8);
}
字符获取字节(void){
而(!(Serial.available()>0)){delay(50);}
返回Serial.read();
}
短接单adr(无效){
adr_lo=获取字节();
adr_hi=获取字节();

return((短)adr_hi您没有告诉我们芯片的确切名称,但我怀疑您使用的是ATmega328P

ATmega328P无法从RAM执行指令。在执行之前,您需要弄清楚如何将代码写入闪存。您可能希望使用引导加载程序将程序写入闪存,或者您可以研究Optiboot以了解其工作原理。请注意,闪存的额定擦除/写入周期数有限(通常为10000)


<> P>也,你的C++语法是错误的。要调用一个函数,你总是需要使用括号。所以你会写<代码> fgf-()/<代码>,而不是只是代码> FGF。< /P> < P>你没有告诉我们你的芯片的确切名称,但是我怀疑你在使用ATMEGA328 P。 ATmega328P无法从RAM执行指令。在执行之前,您需要弄清楚如何将代码写入闪存。您可能希望使用引导加载程序将程序写入闪存,或者您可以研究Optiboot以了解其工作原理。请注意,闪存的额定擦除/写入周期数有限(通常为10000)


<>也,你的C++语法是错误的。要调用一个函数,你总是需要使用括号。所以你会写<代码> fgf-()
。而不仅仅是
fGf

@gre\u-gor:谢谢,-尽管在上面我们试图在运行时使用引导加载的代码本身切换到注入的机器代码。需要的是如何获得代码可以运行的通用头/钩子/容器,以及可以动态注入的机器代码。@gre\u-gor:谢谢,-尽管在上面我们尝试使用引导加载的代码本身在运行时切换到注入的机器代码。需要的是如何获得代码可以运行的通用头/钩子/容器,以及可以动态注入的机器代码。啊哈!那么为什么要使用xstore()和xfetch()呢之所以成功,是因为我将代码注入了mem[255]数组,该数组是在RAM中创建的,因此程序计数器无法使用。这就澄清了xcall没有编译的原因,并且观察到反汇编的ELF文件似乎跳过了fGf()调用。重新语法,这是直接的C(是的,我使用了//comment样式,因为它比//**/更方便,而且Arduino编译器允许使用它)。是的,它是ATmega328(问题的第一行)。非常感谢-接受你的答案!也在Board/ATmega328上分享这一点。Marc Petreman(资深的第四编码器)的文章感谢链接!不管我们是在谈论C还是C++,你需要用括号来调用一个函数。谢谢@ David Grayson ---固定了问题中的代码。AXHA!所以XStule-(和)XFTECHER()的原因是因为我被注入到MEM(255)中。数组,它是在RAM中创建的,因此对程序计数器不可用。这就澄清了xcall没有编译的原因,以及反汇编的ELF文件似乎跳过了fGf()调用的观察结果。重新语法,这是直接的C(是的,我使用了//comment样式,因为它比//**/更方便,而且Arduino编译器允许使用它)。是的,它是ATmega328(问题的第一行)。非常感谢-接受你的答案!也在Board/ATmega328上分享这一点。Marc Petreman(资深的第四编码器)的文章感谢链接!不管我们是在谈论C还是C++,你需要用括号来调用函数。谢谢@ David Grayson ---固定了问题中的代码。