Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Assembly 使用ARM组件闪烁覆盆子pi LED_Assembly_Raspberry Pi_Arm - Fatal编程技术网

Assembly 使用ARM组件闪烁覆盆子pi LED

Assembly 使用ARM组件闪烁覆盆子pi LED,assembly,raspberry-pi,arm,Assembly,Raspberry Pi,Arm,我在尝试将LED连接到raspberry pi上的gpio引脚18时遇到问题。我已经用C测试了我的设置,并确认这不是问题所在,但我的汇编代码才是问题所在 这是我目前掌握的代码: .global main main: SUB SP, SP, #16 @ Create 16 bytes storage LDR R0, .addr_file @ get GPIO Controller addr LDR R1, .flags @ se

我在尝试将LED连接到raspberry pi上的gpio引脚18时遇到问题。我已经用C测试了我的设置,并确认这不是问题所在,但我的汇编代码才是问题所在

这是我目前掌握的代码:

.global main

main:
    SUB SP, SP, #16         @ Create 16 bytes storage
    LDR R0, .addr_file      @ get GPIO Controller addr
    LDR R1, .flags          @ set flag permissions
    BL  open                @ call to get file handle

    STR R0, [SP, #12]       @ File handle number
    LDR R3, [SP, #12]       @ Get File handle
    STR R3, [SP, #0]        @ Store file handle on top stack
    LDR R3, .gpiobase       @ get GPIO_Base address
    STR R3, [SP, #4]        @ store on SP+4
    MOV R0, #0              @ R0=0
    MOV R1, #4096           @ R1=page
    MOV R2, #3              @ R2=3
    MOV R3, #1              @ R3=1 (stdouts)
    BL  mmap                @ call libc fct for mmap

    STR R0, [SP, #16]       @ store virtual mem addr
    LDR R3, [SP, #16]       @ get virtual mem addr

fctsel: 
    ADD R3, R3, #4          @ add 4 for block 1 (GPFSEL1)
    LDR R2, [SP, #16]       @ get virtual mem addr
    ADD R2, R2, #16         @ add 4 for block 1 (GPFSEL1)
    LDR R2, [R2, #0]        @ load R2 with value at R2
    BIC R2, R2, #0b111<<24  @ Bitwise clear of three bits
    STR R2, [R3, #0]        @ Store result in Register [set input]
    LDR R3, [SP, #16]       @ Get virtual mem address
    ADD R3, R3, #4          @ Add 4 for block 1 (GPFSEL1)
    LDR R2, [SP, #16]       @ Get virtual mem addr
    ADD R2, R2, #4          @ add 4 for block 1 (GPFSEL1)
    LDR R2, [R2, #0]        @ Load R2 with value at R2
    ORR R2, R2, #1<<24      @ Set bit....
    STR R2, [R3, #0]        @ ...and make output

on: 
    LDR R3, [SP, #16]       @ get virt mem addr
    MOV R4, #1              @ get 1
    MOV R2, R4, LSL#18      @ Shift by pin number
    STR R2, [R3, #0]        @ write to memory
    LDR R0, [SP, #12]       @ get file handle
    BL  close               @ close file

    ADD SP, SP, #16         @ restore SP

    MOV R7, #1
    SWI 0


.addr_file: .word   .file
.flags:     .word   1576962
@.gpiobase: .word   0x20200000  @ GPIO_Base for Pi 1
.gpiobase:  .word   0x3F200000  @ GPIO_Base for Pi 2

.data
.file:  .ascii "/dev/mem\000"

我设法让它与GPIO 47引脚工作。然而,当我将其更改为使用引脚18时,这就是我遇到问题的地方。提前感谢您的帮助,非常感谢

查看BCM2835文档-Broadcom BCM2835 ARM外围设备

您的代码似乎基于Raspberry Pi,汇编语言,Bruce Smith

我不明白为什么我们要清除3位,因为文件上说是为输入设置的

***我确认它在我的RPi 2 B上工作,针脚上有3+伏电压

目标引脚=18 设置GPIO函数: 26-24 FSEL18 FSEL18-功能选择18 R/W 0 在GPIO备用功能中选择寄存器1 所以:0x 7E20 0004 GPFSEL1 GPIO函数选择1 32 R/W |偏移量0x4

init_output:                        // init for OUTPUT
            ldr r3, [sp, #8]        // virt GPIO base
            add r3, r3, #0x4        // offset to GPFSEL1
            ldr r2, [r3]            // get contents of GPFSEL1
            orr r2, r2, #0b001<<18  // set 3 bits re FSEL18 output
            str r2, [r3]            // store set bits at GPFSEL1
设置输出: 31-0设置n=0..31 0=无效1=设置GPIO引脚n R/W 0 它位于GPIO输出集寄存器0中 So:0x 7E20 001C GPSET0 GPIO引脚输出设置0 32 W |偏移量0x1C==28

set_pin:
        ldr r3, [sp, #8]            // virt GPIO base
        add r3, r3, #0x1C           // GPSET0
        ldr r2, [r3]                // get content of GPSET0
        orr r2, r2, #1<<18          // set PIN 18
        str r2,[r3]                 // set PIN 18 @ GPSET0
清除输出: 31-0 CLRn n=0..31 0=无效1=清除GPIO引脚n R/W 0 哪个是GPIO输出清除寄存器0 So:0x 7E20 0028 GPCLR0 GPIO引脚输出清除0 32 W |偏移量0x28==40

clear_pin:
        ldr r3, [sp, #8]            // virt GPIO base
        add r3, r3, #0x28           // GPCLR0
        ldr r2, [r3]                // get content of GPCLR0
        orr r2, r2, #1<<18          // set PIN 18
        str r2,[r3]                 // set PIN 18 @ GPCLR0            

查看BCM2835文档-Broadcom BCM2835 ARM外围设备

您的代码似乎基于Raspberry Pi,汇编语言,Bruce Smith

我不明白为什么我们要清除3位,因为文件上说是为输入设置的

***我确认它在我的RPi 2 B上工作,针脚上有3+伏电压

目标引脚=18 设置GPIO函数: 26-24 FSEL18 FSEL18-功能选择18 R/W 0 在GPIO备用功能中选择寄存器1 所以:0x 7E20 0004 GPFSEL1 GPIO函数选择1 32 R/W |偏移量0x4

init_output:                        // init for OUTPUT
            ldr r3, [sp, #8]        // virt GPIO base
            add r3, r3, #0x4        // offset to GPFSEL1
            ldr r2, [r3]            // get contents of GPFSEL1
            orr r2, r2, #0b001<<18  // set 3 bits re FSEL18 output
            str r2, [r3]            // store set bits at GPFSEL1
设置输出: 31-0设置n=0..31 0=无效1=设置GPIO引脚n R/W 0 它位于GPIO输出集寄存器0中 So:0x 7E20 001C GPSET0 GPIO引脚输出设置0 32 W |偏移量0x1C==28

set_pin:
        ldr r3, [sp, #8]            // virt GPIO base
        add r3, r3, #0x1C           // GPSET0
        ldr r2, [r3]                // get content of GPSET0
        orr r2, r2, #1<<18          // set PIN 18
        str r2,[r3]                 // set PIN 18 @ GPSET0
清除输出: 31-0 CLRn n=0..31 0=无效1=清除GPIO引脚n R/W 0 哪个是GPIO输出清除寄存器0 So:0x 7E20 0028 GPCLR0 GPIO引脚输出清除0 32 W |偏移量0x28==40

clear_pin:
        ldr r3, [sp, #8]            // virt GPIO base
        add r3, r3, #0x28           // GPCLR0
        ldr r2, [r3]                // get content of GPCLR0
        orr r2, r2, #1<<18          // set PIN 18
        str r2,[r3]                 // set PIN 18 @ GPCLR0            

这里有一个修改后的备选答案,用C

由InfinitelyManic澄清的解决方案在Pi-0运行拉伸上运行良好。set操作在运行Jessie K 4.9.35或Openelec 8.0.4=Kodi 17.3内核4.9.30的Pi-1B上运行良好,但clear操作清除了pin,但挂起了系统

我使用合并自fdbdcbc和InfinitelyManic的汇编代码作为C过程的原型来做同样的事情。我的希望是C版本可能更易于移植。它使用上述技术对管脚进行直接内存控制,而不使用wiringPi或其他库,这是我无法加载到Openelec上的。在调试中,我发现设置SET/CLR寄存器只需要写入表示要设置/CLR的管脚的一位;复制和重写寄存器导致系统挂起CLR

我已经对一些代码进行了大量的注释,并使用标准的C包含定义将其从汇编程序反向工程到C

下面的代码适用于运行Stretch的Pi-0版本代码920093和运行Jessie或Openelec的Pi-1B版本代码000e

/*  gblink.c
    Procedures to set and clear Raspberry Pi GPIO pins through direct
    memory access rather than through major libraries (such as wiringPi).

    Advantages: speed and portability (requiring no special libraries).
    Disadvantage: limited capability, long-term maintenance, flexibility.

    If running on Pi-2, change ref to gpioBASE to gpioBASE2 in mmap call
    Don't know what to use if Pi-3

    With testing program.
    Compile as
        gcc -o gblink gblink.c
    run as
        sudo gblink <pin number>

    Written by hdtodd, 12 Dec 2017, based on Stack Overflow ARM 
    assembler examples by InfinitelyManic on 10 Mar 2017:
    https://stackoverflow.com/questions/42702056/
      flash-raspberry-pi-led-using-arm-assembly
    Corrected 23 Dec 2017 to write rather than rewrite SET/CLR registers.

    See also: 
      https://www.raspberrypi.org/app/uploads/2012/02/BCM2835-ARM-Peripherals.pdf
*/

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <ctype.h>
#include <strings.h>
#include <time.h>
#include <signal.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>

#define memFile    "/dev/mem"            // memory device for mapping
#define memFlags   O_RDWR | O_SYNC       // flags for opening mem
#define baseGPIO   0x20200000            // GPIO_Base address for Pi 1
#define baseGPIO2  0x3F200000            // GPIO_Base address for Pi 2
#define pinMAX     32                    // max # of GPIO pins we'll support (for simplicity)
#define pinsPerSEL 10                    // 3 bits/field, 10 fields/register in GFSELn's
#define outMask    0b111                 // 3-bit field mask to clear GFSEL register
#define outEnable  0b001                 // 3-bit pattern for GFSEL registers to enable output
#define offsetSET   7                    // word-address offset to GPSET0 word to set pin (0x1c bytes)
#define offsetCLR  10                    // word-address offset to GPCLR0 word to clear pin (0x28 bytes)
typedef enum {false=0, true=~0} boolean;

static uint32_t  *vAddrGPIO;             // mapped address to physical GPIO register base
int       memFH;                         // file handle for /dev/mem 
boolean   alreadyMapped = false;
boolean   keepBlinking = true;
struct sigaction act;                    // catch CNTL-C to terminate cleanly
uint32_t  gpFSEL, fSELn;                 // offset to GPIO Function SELect register for this 
                                         //   pin & Field SEL loc in that register for this pin
boolean   gblinkDebug = false;           // enables printing debug information

// cntlCHandler() triggers end of main loop if a ^C is received on controlling terminal
void cntlCHandler(int sigType) {
  keepBlinking = false;
};

// enableGPIO maps memory to GPIO registers and sets pin 'pinNum' to be an output pin
boolean enableGPIO(int pinNum) {
  if (pinNum < 0 || pinNum > pinMAX-1) {
    printf("[enableGPIO:] Requested pin # %d out of range 0 to %d\n", pinNum, pinMAX-1);
    return false;
  };

  // if we haven't already done it, map GPIO registers to our memory space
  if ( !alreadyMapped ) {
    if ( (memFH = open(memFile,memFlags)) < 0) {
      perror("[?enableGPIO:] Can't open '/dev/mem' file; exiting.  Rerun as root?");
      exit(EXIT_FAILURE);
    }
    vAddrGPIO = (uint32_t *)mmap(NULL,getpagesize(),PROT_WRITE|PROT_READ,MAP_SHARED,memFH,baseGPIO);
    if (vAddrGPIO == MAP_FAILED) {
      perror("[?enableGPIO:] Can't map to GPIO register addresses; exiting.  Rerun as root?");
      exit(EXIT_FAILURE);
    };
    alreadyMapped = true;
  };

  // locate the register and field for this pin and set it for output
  if (gblinkDebug) 
    printf("[enableGPIO] Memory-mapped base address of GPIO register set is vAddrGPIO = %p\n", vAddrGPIO);
  gpFSEL  = pinNum/pinsPerSEL;          // offset to register for this pin
  fSELn   = 3*(pinNum%pinsPerSEL);      // location in register of 3-bit field for this pin
  if (gblinkDebug) {
    printf("[enableGPIO] GPIO pin mapped to GPFSEL%d and 3-bit FSEL field at bit %d in that register.\n", gpFSEL, fSELn);
    printf("[enableGPIO] Will use gpioSEL register at %p\n", (vAddrGPIO+gpFSEL));
  };
  *(vAddrGPIO+gpFSEL) =  ( *(vAddrGPIO+gpFSEL) & ~(outMask<<fSELn)) | (outEnable<<fSELn);
  if (gblinkDebug)
    printf("[enableGPIO] After setting, GPFSEL%d register contents = %x\n", gpFSEL, *(vAddrGPIO+gpFSEL));
  return true;
};

// sets the pin voltage high (+5v)
boolean setOutput(int pinNum) {
  if (pinNum < 0 || pinNum >= pinMAX) {
    printf("[setOutput] Requested pin # %d is outside of allowed range 0 to %d\n", pinNum, pinMAX-1);
    return false;
  };
  if (gblinkDebug)
    printf("[setOutput] Writing to pin field %d at GPIO register address %p\n", pinNum, (vAddrGPIO+offsetSET));
  *(vAddrGPIO+offsetSET) = 1<<pinNum;  // write to "set" bit
  return true;
};

// sets the pin voltage low (+0v)
boolean clrOutput(int pinNum) {
  if (pinNum < 0 || pinNum >= pinMAX) {
    printf("[clrOutput] Requested pin # %d is outside of allowed range 0 to %d\n", pinNum, pinMAX-1);
    return false;
  };
  if (gblinkDebug)
    printf("[clrOutput] Writing to pin field %d at GPIO register address %p\n", pinNum, (vAddrGPIO+offsetCLR));
  *(vAddrGPIO+offsetCLR) = 1<<pinNum; // write to "clr" bit
  return true;
};

void main(int argc, char *argv[]) {
  int pinNum;

  // validate arguments and/or provide help
  if ( (argc < 2) || (strcasecmp(argv[1],"-h")==0) || !isdigit(argv[1][0]) ) {
    printf("gblink: program to test direct memory control of GPIO pins by toggling pin voltage high<-->low\n");
    printf("        usage: gblink [ pin number, >=0, <=%d ]\n", pinMAX-1);
    printf("               where pin number is BCM2835 numbering system.  Not GPIO or Pi!\n");
    printf("        Install wiringPi and run 'gpio readall' to see pin map\n");
    printf("        Debug with 'sudo GBLINK_DEBUG=1 gblink <pin number>'\n");
    return;
  };

  // we need to run as root to open and map memory
  if (geteuid() != 0) {
    fprintf(stderr, "[?%s:] Must be run as root.  Try 'sudo %s <pin number>'\n", argv[0], argv[0]);
    exit(EXIT_FAILURE);
  };

  // do we want to provide debugging information along the way?
  if (getenv("GBLINK_DEBUG") != NULL) {
    printf("[gblink:] Debug mode enabled\n");
    gblinkDebug = true;
  };

  // OK, ready to go.  Catch ^C's to exit cleanly
  act.sa_handler = cntlCHandler;
  sigaction(SIGINT, &act, NULL);

  // which pin are we working with?
  pinNum = atoi(argv[1]);
  if (gblinkDebug)
    printf("[gblink:] Using GPIO pin %d\n", pinNum);

  // enable that pin for output
  if ( !enableGPIO(pinNum) ) {
    perror("[gblink:] Can't enable GPIO output.  ");
    exit(EXIT_FAILURE);
  };

  // until we're told to stop, just keep blinking
  while (keepBlinking) {
    if (gblinkDebug) printf("[gblink:] Turning pin ON\n");
    setOutput(pinNum);
    sleep(2);
    if (gblinkDebug) printf("[gblink:] Turning pin OFF\n");
    clrOutput(pinNum);
    sleep(5);
  };

  /* ^C terminate the loop above and drops into this cleanup code */
  printf("[gblink:] CNTL-C halt.  Clean up and exit.\n");
  if (alreadyMapped) {
    munmap(vAddrGPIO,getpagesize());
    close(memFH);
  };

  return;
};

这里有一个修改后的备选答案,用C

由InfinitelyManic澄清的解决方案在Pi-0运行拉伸上运行良好。set操作在运行Jessie K 4.9.35或Openelec 8.0.4=Kodi 17.3内核4.9.30的Pi-1B上运行良好,但clear操作清除了pin,但挂起了系统

我使用合并自fdbdcbc和InfinitelyManic的汇编代码作为C过程的原型来做同样的事情。我的希望是C版本可能更易于移植。它使用上述技术对管脚进行直接内存控制,而不使用wiringPi或其他库,这是我无法加载到Openelec上的。在调试中,我发现设置SET/CLR寄存器只需要写入表示要设置/CLR的管脚的一位;复制和重写寄存器导致系统挂起CLR

我已经对一些代码进行了大量的注释,并使用标准的C包含定义将其从汇编程序反向工程到C

下面的代码适用于运行Stretch的Pi-0版本代码920093和运行Jessie或Openelec的Pi-1B版本代码000e

/*  gblink.c
    Procedures to set and clear Raspberry Pi GPIO pins through direct
    memory access rather than through major libraries (such as wiringPi).

    Advantages: speed and portability (requiring no special libraries).
    Disadvantage: limited capability, long-term maintenance, flexibility.

    If running on Pi-2, change ref to gpioBASE to gpioBASE2 in mmap call
    Don't know what to use if Pi-3

    With testing program.
    Compile as
        gcc -o gblink gblink.c
    run as
        sudo gblink <pin number>

    Written by hdtodd, 12 Dec 2017, based on Stack Overflow ARM 
    assembler examples by InfinitelyManic on 10 Mar 2017:
    https://stackoverflow.com/questions/42702056/
      flash-raspberry-pi-led-using-arm-assembly
    Corrected 23 Dec 2017 to write rather than rewrite SET/CLR registers.

    See also: 
      https://www.raspberrypi.org/app/uploads/2012/02/BCM2835-ARM-Peripherals.pdf
*/

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <ctype.h>
#include <strings.h>
#include <time.h>
#include <signal.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>

#define memFile    "/dev/mem"            // memory device for mapping
#define memFlags   O_RDWR | O_SYNC       // flags for opening mem
#define baseGPIO   0x20200000            // GPIO_Base address for Pi 1
#define baseGPIO2  0x3F200000            // GPIO_Base address for Pi 2
#define pinMAX     32                    // max # of GPIO pins we'll support (for simplicity)
#define pinsPerSEL 10                    // 3 bits/field, 10 fields/register in GFSELn's
#define outMask    0b111                 // 3-bit field mask to clear GFSEL register
#define outEnable  0b001                 // 3-bit pattern for GFSEL registers to enable output
#define offsetSET   7                    // word-address offset to GPSET0 word to set pin (0x1c bytes)
#define offsetCLR  10                    // word-address offset to GPCLR0 word to clear pin (0x28 bytes)
typedef enum {false=0, true=~0} boolean;

static uint32_t  *vAddrGPIO;             // mapped address to physical GPIO register base
int       memFH;                         // file handle for /dev/mem 
boolean   alreadyMapped = false;
boolean   keepBlinking = true;
struct sigaction act;                    // catch CNTL-C to terminate cleanly
uint32_t  gpFSEL, fSELn;                 // offset to GPIO Function SELect register for this 
                                         //   pin & Field SEL loc in that register for this pin
boolean   gblinkDebug = false;           // enables printing debug information

// cntlCHandler() triggers end of main loop if a ^C is received on controlling terminal
void cntlCHandler(int sigType) {
  keepBlinking = false;
};

// enableGPIO maps memory to GPIO registers and sets pin 'pinNum' to be an output pin
boolean enableGPIO(int pinNum) {
  if (pinNum < 0 || pinNum > pinMAX-1) {
    printf("[enableGPIO:] Requested pin # %d out of range 0 to %d\n", pinNum, pinMAX-1);
    return false;
  };

  // if we haven't already done it, map GPIO registers to our memory space
  if ( !alreadyMapped ) {
    if ( (memFH = open(memFile,memFlags)) < 0) {
      perror("[?enableGPIO:] Can't open '/dev/mem' file; exiting.  Rerun as root?");
      exit(EXIT_FAILURE);
    }
    vAddrGPIO = (uint32_t *)mmap(NULL,getpagesize(),PROT_WRITE|PROT_READ,MAP_SHARED,memFH,baseGPIO);
    if (vAddrGPIO == MAP_FAILED) {
      perror("[?enableGPIO:] Can't map to GPIO register addresses; exiting.  Rerun as root?");
      exit(EXIT_FAILURE);
    };
    alreadyMapped = true;
  };

  // locate the register and field for this pin and set it for output
  if (gblinkDebug) 
    printf("[enableGPIO] Memory-mapped base address of GPIO register set is vAddrGPIO = %p\n", vAddrGPIO);
  gpFSEL  = pinNum/pinsPerSEL;          // offset to register for this pin
  fSELn   = 3*(pinNum%pinsPerSEL);      // location in register of 3-bit field for this pin
  if (gblinkDebug) {
    printf("[enableGPIO] GPIO pin mapped to GPFSEL%d and 3-bit FSEL field at bit %d in that register.\n", gpFSEL, fSELn);
    printf("[enableGPIO] Will use gpioSEL register at %p\n", (vAddrGPIO+gpFSEL));
  };
  *(vAddrGPIO+gpFSEL) =  ( *(vAddrGPIO+gpFSEL) & ~(outMask<<fSELn)) | (outEnable<<fSELn);
  if (gblinkDebug)
    printf("[enableGPIO] After setting, GPFSEL%d register contents = %x\n", gpFSEL, *(vAddrGPIO+gpFSEL));
  return true;
};

// sets the pin voltage high (+5v)
boolean setOutput(int pinNum) {
  if (pinNum < 0 || pinNum >= pinMAX) {
    printf("[setOutput] Requested pin # %d is outside of allowed range 0 to %d\n", pinNum, pinMAX-1);
    return false;
  };
  if (gblinkDebug)
    printf("[setOutput] Writing to pin field %d at GPIO register address %p\n", pinNum, (vAddrGPIO+offsetSET));
  *(vAddrGPIO+offsetSET) = 1<<pinNum;  // write to "set" bit
  return true;
};

// sets the pin voltage low (+0v)
boolean clrOutput(int pinNum) {
  if (pinNum < 0 || pinNum >= pinMAX) {
    printf("[clrOutput] Requested pin # %d is outside of allowed range 0 to %d\n", pinNum, pinMAX-1);
    return false;
  };
  if (gblinkDebug)
    printf("[clrOutput] Writing to pin field %d at GPIO register address %p\n", pinNum, (vAddrGPIO+offsetCLR));
  *(vAddrGPIO+offsetCLR) = 1<<pinNum; // write to "clr" bit
  return true;
};

void main(int argc, char *argv[]) {
  int pinNum;

  // validate arguments and/or provide help
  if ( (argc < 2) || (strcasecmp(argv[1],"-h")==0) || !isdigit(argv[1][0]) ) {
    printf("gblink: program to test direct memory control of GPIO pins by toggling pin voltage high<-->low\n");
    printf("        usage: gblink [ pin number, >=0, <=%d ]\n", pinMAX-1);
    printf("               where pin number is BCM2835 numbering system.  Not GPIO or Pi!\n");
    printf("        Install wiringPi and run 'gpio readall' to see pin map\n");
    printf("        Debug with 'sudo GBLINK_DEBUG=1 gblink <pin number>'\n");
    return;
  };

  // we need to run as root to open and map memory
  if (geteuid() != 0) {
    fprintf(stderr, "[?%s:] Must be run as root.  Try 'sudo %s <pin number>'\n", argv[0], argv[0]);
    exit(EXIT_FAILURE);
  };

  // do we want to provide debugging information along the way?
  if (getenv("GBLINK_DEBUG") != NULL) {
    printf("[gblink:] Debug mode enabled\n");
    gblinkDebug = true;
  };

  // OK, ready to go.  Catch ^C's to exit cleanly
  act.sa_handler = cntlCHandler;
  sigaction(SIGINT, &act, NULL);

  // which pin are we working with?
  pinNum = atoi(argv[1]);
  if (gblinkDebug)
    printf("[gblink:] Using GPIO pin %d\n", pinNum);

  // enable that pin for output
  if ( !enableGPIO(pinNum) ) {
    perror("[gblink:] Can't enable GPIO output.  ");
    exit(EXIT_FAILURE);
  };

  // until we're told to stop, just keep blinking
  while (keepBlinking) {
    if (gblinkDebug) printf("[gblink:] Turning pin ON\n");
    setOutput(pinNum);
    sleep(2);
    if (gblinkDebug) printf("[gblink:] Turning pin OFF\n");
    clrOutput(pinNum);
    sleep(5);
  };

  /* ^C terminate the loop above and drops into this cleanup code */
  printf("[gblink:] CNTL-C halt.  Clean up and exit.\n");
  if (alreadyMapped) {
    munmap(vAddrGPIO,getpagesize());
    close(memFH);
  };

  return;
};

我认为需要对上面的InfinitelyManic代码进行一点修改

在set_pin:/clear_pin:节中,而不是

//        ldr r2, [r3]          // get content of GPCLR0                                                                            
//        orr r2, r2, #1<<23    // set PIN 23 to 1 ==> set pin voltage to low
也就是说,写入而不是复制和重写该寄存器。我将限流电阻器连接到23,而不是像InfinitelyManic那样使用引脚18。为SEL和SET/CLR寄存器引用相应地调整您自己的代码

此更改仅设置SET/CLR寄存器wr中的一位 将其他位设置为0,而不是复制然后重写整个寄存器,这可能会再次设置其他位。我本以为重写一些其他代码正在管理并已经设置的位不会有什么坏处,但并非所有的Raspberry Pi模型都是这样。数据表对此非常清楚:将1写入寄存器插槽会导致引脚电压被设置或重置。不清楚的是,在不同型号的Pi上,该寄存器中表示的其他引脚可能连接到其他硬件,再次设置/清除它们可能会在这些设备中产生意外后果

InfinitelyManic复制和重写寄存器的代码在Pi-0模型修订代码920093上工作,正如我先前的C翻译文章一样,随后根据此更改进行了编辑。但在Pi-1B修订代码000e上,该装置工作,但CLR失败。或者,更确切地说,CLR将该引脚上的电压重置为0,但同时也挂起了系统,迫使电源循环


大量的实验导致了一种说法——复制和重写而不是仅仅写作——成为问题的根源。在运行Stretch的Pi-0、K 4.9.66+、运行Jessie的Pi-1B、K 4.9.35和运行Openelec 8.0.4 aka Kodi 17.3、K 4.9.30的Pi-1B上测试并验证了两个版本的代码。这两种形式的代码都在Pi-0上运行;复制和重写版本将Jessie和Openelec挂在Pi-1B上。

我认为需要对上面的InfinitelyManic代码进行一点修改

在set_pin:/clear_pin:节中,而不是

//        ldr r2, [r3]          // get content of GPCLR0                                                                            
//        orr r2, r2, #1<<23    // set PIN 23 to 1 ==> set pin voltage to low
也就是说,写入而不是复制和重写该寄存器。我将限流电阻器连接到23,而不是像InfinitelyManic那样使用引脚18。为SEL和SET/CLR寄存器引用相应地调整您自己的代码

此更改仅设置SET/CLR寄存器中的一位,将其他位写入为0,而不是复制然后重写整个寄存器,这可能会再次设置其他位。我本以为重写一些其他代码正在管理并已经设置的位不会有什么坏处,但并非所有的Raspberry Pi模型都是这样。数据表对此非常清楚:将1写入寄存器插槽会导致引脚电压被设置或重置。不清楚的是,在不同型号的Pi上,该寄存器中表示的其他引脚可能连接到其他硬件,再次设置/清除它们可能会在这些设备中产生意外后果

InfinitelyManic复制和重写寄存器的代码在Pi-0模型修订代码920093上工作,正如我先前的C翻译文章一样,随后根据此更改进行了编辑。但在Pi-1B修订代码000e上,该装置工作,但CLR失败。或者,更确切地说,CLR将该引脚上的电压重置为0,但同时也挂起了系统,迫使电源循环


大量的实验导致了一种说法——复制和重写而不是仅仅写作——成为问题的根源。在运行Stretch的Pi-0、K 4.9.66+、运行Jessie的Pi-1B、K 4.9.35和运行Openelec 8.0.4 aka Kodi 17.3、K 4.9.30的Pi-1B上测试并验证了两个版本的代码。这两种形式的代码都在Pi-0上运行;复制和重写版本将Jessie和Openelec挂在Pi-1B上。

忘了问你使用的是哪种覆盆子Pi。GPIO引脚布局很重要,它们都不一样。您是否使用存储/重新加载STR R0、[SP,16]/LDR R3、[SP,16]作为某种故意延迟?如果不是,那么未优化的编译器生成的代码就不是一个很好的例子。它在C语句之间溢出/重新加载到内存,仅支持在断点处停止时使用调试器修改C变量。普通代码应该只在寄存器中保存变量;ARM有16台,其中14台为通用型。无论如何,我认为您不需要将任何内容泄漏到内存中,因此唯一的存储应该是实际的MMIO写入。从仅链接回答:描述GPIO引脚,可能有用。忘了问您使用的是哪种覆盆子Pi。GPIO引脚布局很重要,它们都不一样。您是否使用存储/重新加载STR R0、[SP,16]/LDR R3、[SP,16]作为某种故意延迟?如果不是,那么未优化的编译器生成的代码就不是一个很好的例子。它在C语句之间溢出/重新加载到内存,仅支持在断点处停止时使用调试器修改C变量。普通代码应该只在寄存器中保存变量;ARM有16台,其中14台为通用型。无论如何,我认为你不需要把任何东西泄漏到内存中,所以唯一的存储应该是实际的MMIO写入。从一个只链接的答案:描述GPIO引脚,可能有用。谢谢你的帮助,我很感激!谢谢你的帮助,我很感激!为了更好地处理错误,可以使用perror而不是printf来解码errno。以非根用户身份运行时,可能会得到错误的文件句柄,因为memFH将是-1。当然,使用strace./a.out会提供更多信息,这是
在简单的工具中编写完整的错误检测的替代方法,如:Pexit;不会退出进程,但会编译。这与编写void&exit是一样的,因为exit是一个库函数。我想你想要离开;你应该从墙上得到一个关于一个没有效果的声明的警告,因为你没有把它作废。谢谢,彼得。这两个建议结合在一起,我找到了挂起的来源。为了更好地处理错误,您可以使用perror而不是printf来解码errno。以非根用户身份运行时,可能会得到错误的文件句柄,因为memFH将是-1。当然,使用strace./a.out会给您提供更多信息,并且是在像这样的简单工具中编写完整错误检测的懒惰替代品:Pexit;不会退出进程,但会编译。这与编写void&exit是一样的,因为exit是一个库函数。我想你想要离开;你应该从墙上得到一个关于一个没有效果的声明的警告,因为你没有把它作废。谢谢,彼得。这两个建议结合在一起,我找到了挂起的来源。我认为ORRing为了设置/清除目标位不会设置/清除任何其他位。将1写入set或CLR寄存器中的任何位将分别设置相应的引脚高或低。我认为重写位是一种方法,复制SET或CLR寄存器,将要设置/CLR的管脚的位设置为1,然后重写寄存器,因为除了所需的位/管脚之外,您不会改变任何东西。这在Pi-0上似乎效果很好。但Pi-1B的接线方式似乎有点不同,重写CLR寄存器中的一些其他位似乎会影响BCM连接的其他硬件。我的设备是运行Debian的Pi 2型号B Rev 1.1;技术上是BCM2836。我认为当时没有BCM2836文档可用/发布。尽管如此,我的Pi并没有被锁定。干得好。我认为ORRing为了设置/清除目标位不会设置/清除任何其他位。将1写入set或CLR寄存器中的任何位将分别设置相应的引脚高或低。我认为重写位是一种方法,复制SET或CLR寄存器,将要设置/CLR的管脚的位设置为1,然后重写寄存器,因为除了所需的位/管脚之外,您不会改变任何东西。这在Pi-0上似乎效果很好。但Pi-1B的接线方式似乎有点不同,重写CLR寄存器中的一些其他位似乎会影响BCM连接的其他硬件。我的设备是运行Debian的Pi 2型号B Rev 1.1;技术上是BCM2836。我认为当时没有BCM2836文档可用/发布。尽管如此,我的Pi并没有被锁定。干得好。