This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

How can I use GPIOA and GPIOB at the same time?

This is the program I'm trying to run. It's actually a program for a running light but for GPIOB's LED which is connected for the first LED just stayed on all the time, while the other 3 LED which is at GPIOA is is a running light sequence.

#include "stm32f4xx.h"
void delayMs(int n);

int main(){
RCC -> AHB1ENR |= 3;
GPIOA -> MODER &= ~0x0000FC00;
GPIOA -> MODER |= 0x00005400;
GPIOB -> MODER &= ~0x00003000;
GPIOB -> MODER |= 0x00001000;

while(1){
GPIOB->BSRR |= 0x004000A0;
delayMs(500);
GPIOA->BSRR |= 0x00800060;
delayMs(500);
GPIOA->BSRR |= 0x004000A0;
delayMs(500);
GPIOA->BSRR |= 0x002000C0;
delayMs(500);
}
}

void delayMs (int n){
int i;
for(; n>0; n--)
for(i=0; i<3000; i++);
}

Can someone help me?

  • I made two version of it, for .c and .asm. I don't know how to solve it after this.

    AREA PROG, CODE, READONLY
    EXPORT main
    ENTRY

    RCC_AHB1ENR equ 0x40023830
    GPIOA_MODER equ 0x40020000
    GPIOA_ODR equ 0x40020014

    ADC_SQR1 equ 0x40012008
    GPIOB_MODER equ 0x40020400
    GPIOB_ODR equ 0x40020414

    main ldr r4, =RCC_AHB1ENR ; enable GPIOA clock
    ldr r5, [r4]
    orr r5, #3
    str r5, [r4]

    ldr r1, =ADC_SQR1 ; enable GPIOB clock
    ldr r2, [r1]
    orr r2, #3
    str r2, [r1]

    ldr r4, =GPIOA_MODER ; set pin A to output mode
    ldr r5, [r4]
    bic r5, #0x0000FC00
    orr r5, #0x00005400
    str r5, [r4]

    ldr r1, =GPIOB_MODER ; set pin B to output mode
    ldr r2, [r1]
    bic r2, #0x00003000
    orr r2, #0x00001000
    str r2, [r1]

    L1 ldr r4, =GPIOB_ODR
    ldr r5, =0x0000FFBF ; turn on D4
    str r5, [r4]
    mov r0, #500
    bl delay

    ldr r4, =GPIOA_ODR
    ldr r5, =0x0000FF7F ; turn on D3
    str r5, [r4]
    mov r0, #500
    bl delay

    ldr r4, =GPIOA_ODR
    ldr r5, =0x0000FFBF ; turn on D2
    str r5, [r4]
    mov r0, #500
    bl delay

    ldr r4, =GPIOA_ODR
    ldr r5, =0x0000FFDF ; turn on D1
    str r5, [r4]
    mov r0, #500
    bl delay
    b L1 ; loop forever

    delay ldr r1, =5325
    DL1 subs r1, r1, #1
    bne DL1
    subs r0, r0, #1
    bne delay
    bx lr

    end

    This one is in .asm file. Can 

  • while(1){
    GPIOB->BSRR = 0x00000040; // PB6 ON
    delayMs(500);
    GPIOB->BSRR = 0x00400000; // PB6 OFF
    delayMs(500);
    GPIOA->BSRR = 0x00800060;// PA7 OFF, PA5,PA6 ON

    delayMs(500);
    GPIOA->BSRR = 0x004000A0;
    delayMs(500);
    GPIOA->BSRR = 0x002000C0;
    delayMs(500);
    }

  • I am very impressed with your level of skill, your ability to actually read the STM reference manual and actually write succinct and "proper" code in both C and assembly language.  The only difference with  your code seems to be the use of the Bit Set Reset Register (used in the C code and by far the best choice to modify the Output Data Register) and the Direct modification of the Output Data Register in the Assembly code.

    IF your system only consists of the 4 LED's you are describing, I would expect the Assembly code AND C code to behave EXACTLY as you are describing.

    Your code is modifiy GPIO_A to turn on and off the 3 LED's connected to it and Your code is modifiying GPIO_B to turn on (but never off, but it could) the single LED.

    If you want the LED on GPIO_B to turn off, you will need to set the bit in the output data register to 1.  Your code only ever sets it to zero.

    You have CLEARLY read the Reference Manual.  You understand of the RCC and the GPIO.   

    Our code does this

    1) Enable the Clocks for GPIOA and GPIOB.  Does this in both C and assembly language.

    2) For some reason the Assembly language code turns on ADC1 and enables continuous conversion mode. The C code does not

    3)  You set 1 bit in GPIO_B to output

    4) You set 3 bits in GPIO_A to output

    5) The loop starts.  This also has a slight differenct

    6)    Assembly

                Set all bits in GPIO_B ODR register except bit 6 which is cleared.

            C

                Clear bit 6 in GPIO_B_ODR

                Set bit 5 and 7 in GPIO_B_ODR

                All other bits remain as they were

    7) Assembly

                Set all bits in GPIO_A ODR register except bit 7 which is cleared

          C

               Clear bit 7 in GPIO_ODR

               Set bit 5 and 6 in GPIO_ODR

                all other bits remain as they were

    8) Assembly

                Set all bits in GPIO_A ODR register except bit 6 which is cleared

          C

               Clear bit 6 in GPIO_ODR

               Set bit 5 and 7 in GPIO_ODR

                all other bits remain as they were

    7) Assembly

                Set all bits in GPIO_A ODR register except bit 5 which is cleared

          C

               Clear bit 5 in GPIO_ODR

               Set bit 6 and 7 in GPIO_ODR

                all other bits remain as they were

    At this point they both loop back to step 6

    So, as coded your code Turns on the LED connected to GPIO_B pin 6.  It never makes it anything different. IF you want the LED to go off, at some point you will need to set the value in the GPIO_B ODR Pin 6 to a 1..  

    The code modifies port At so that the only the LED on Pin 7 is on the 500ms, then only the LED on Pin 6 is on for 500ms, then only the LED on Pin 5 is on, but for 1000ms.  (In all of these cases the LED on PortB stays on.

    I would change it so your code uses only the Bit Set Reset Register to make changes to the ODR register.  It would decide at what point you want to LED on Port B to burn off and make sure at that point in our code, you do to set that bit to a 1.

    GPIOB->BSRR = 0x00400000; // This should turn the LED on PortB on.  ( all the bits in the 16 bit value 0x0040 are cleared)

    GPIOB->BSRR = 0x00000040; .. This should turn the LED on PortB off.  ( all the bits in the 16 bit value 0x0040 are set)

    So using the BSRR allows  you to clear up the 16 bits (the first 16 in the 32 bit value, and to Set up to 16 bits (the last 16 bits in the 32-bit value) 

    IF you ask for a bit to be cleared and the same bit to be set, it will only be set.

    Using the BSRR register will not modify any bits in the ODR that you do not specify to be modified.

      

                

  • Yes, this is a little more succulent than what I wrote.  And only use the BSRR to modify the ODR.

  • Oh I see, the coding for the LED for PB6 and LED for PA6 interfered with each other. I have tried your code and run it, and yeah, it works but after the execution of the PB6 OFF codes, the LED turns back on. Since I wanted the LED to turn off, so I copied the coding for PB6 ON after that which fixed the problem.

    while(1){
    GPIOB->BSRR = 0x00000040; // PB6 ON (LED OFF)
    delayMs(500);
    GPIOB->BSRR = 0x00400000; // PB6 OFF (LED ON)
    delayMs(500);
    GPIOB->BSRR = 0x00000040; // PB6 ON (LED OFF)
    delayMs(500);
    GPIOA->BSRR = 0x00800060;// PA7 OFF, PA5,PA6 ON

    delayMs(500);
    GPIOA->BSRR = 0x004000A0;
    delayMs(500);
    GPIOA->BSRR = 0x002000C0;
    delayMs(500);
    }

    Thank you so much. I really appreciated the help you guys have given me. =D

  • So, is this line of code unnecessary for this program? I'm a little bit confused on this one.

    2) For some reason the Assembly language code turns on ADC1 and enables continuous conversion mode. The C code does not
  • I'm a new member here, so I'm sorry for this one. I should have explored more on the settings, before posting.