I try to learn STM32 MCU programming and at the beginning I'd like to mark, that't I'm totally begginer in it, so please forgive me some mistakes (also language mistakes).
So I'm using STM32F103RBT6 (Nucleo-64) Board and I wanted to implement an excercise with 4x3 Matrix Keypad as shown below:
When some key from this matrix is pressed it should be printed in program. After writing and testing code using tool 'SWV ITM Data Console' in STM32CubeIDE it prints over and over, like in some loop, characters #,3,5,6,9 without pressing actually any key on the keypad. When I press some other button like '1' or '2' it's also printed "between" metioned above characters. My program works the way, that every column is set as an Input and every row as Output. Columns are in Pull-up Mode (with internal pull-up resistors) and at the beginning all rows are in High state. Next I make in turn every row Low to check if any of 3 columns is Low and, if need be, print that one's character.I use PC0, PC1, PC2 and PC3 I/O Pins as output for Rows (PC0 - first row from the top, PC1 - 2nd, and so on...) and PA0, PA1, PA4 as Input for Columns (PA0 - 1st from the left, PA1 - 2nd and PA4 - 3rd). The checking of rows and columns is made in a while loop. Below is my main.c code (I had some trouble pasting it in one piece, forgive me):
#include <stdint.h>
#include <stdio.h>
void delay (void)
{
for(int i = 0; i < 300000; i++);
}
int main(void)
{
/* MEMORY (BASIC) addresses:
* 0x4002 1000 - 0x4002 13FF Reset and clock control RCC
* 0x4001 0800 - 0x4001 0BFF GPIO Port A
* 0x4001 1000 - 0x4001 13FF GPIO Port C
*/
//Address offset are added
//Clock for all used Pins
uint32_t volatile *const p_Clk_reg = (uint32_t*) (0x40021000 + 0x18);
// PAx Pins:
uint32_t volatile *p_PortA_Mode_reg = (uint32_t*) 0x40010800;
uint32_t volatile *p_PortA_In_reg = (uint32_t*) (0x40010800 + 0x08);
uint32_t volatile *p_Pullup_Pulldown_reg = (uint32_t*) 0x40010800;
//PCx Pins:
uint32_t volatile *p_PortC_Mode_reg = (uint32_t*) 0x40011000;
uint32_t volatile *p_PortC_Out_reg = (uint32_t*) (0x40010800 + 0x0C);
//Set clock signal for GPIOA/C:
*p_Clk_reg |= (0x5 << 2);
//------------------ Initialization for PAx Pins (COLUMNS) -----------------------
//1. Clear appropriate bits
// PA0:
*p_PortA_Mode_reg &= (~0xF);
// PA1:
*p_PortA_Mode_reg &= (~(0xF << 4));
// PA4:
*p_PortA_Mode_reg &= (~(0xF << 16));
//2a. Set the INPUT mode
//There's nothing to be done, because to set INPUT bits MODE[1..0] must be = "00"
//and above we set all appropriate bits as '0'(Is it OK?)
//2b. Set the PULL-UP Mode for PA0, PA1, PA4 (Inputs) - CNF[1..0] must be "10"
*p_Pullup_Pulldown_reg |= (1 << 3);
*p_Pullup_Pulldown_reg |= (1 << 7);
*p_Pullup_Pulldown_reg |= (1 << 19);
//----------------------------------------------------------------------
//------------------ Initialization for PCx Pins (ROWS) -----------------------
//1. Clear appropriate bits
// PC0:
*p_PortC_Mode_reg &= (~0xF);
// PC1:
*p_PortC_Mode_reg &= (~(0xF << 4));
// PC2:
*p_PortC_Mode_reg &= (~(0xF << 8));
// PC3:
*p_PortC_Mode_reg &= (~(0xF << 12));
//2. Set the Push-pull OUTPUT mode
// so from table 20. when there's CNF1_CNF0_MODE1_MODE0 it must be sequence "0001"
*p_PortC_Mode_reg |= (1); //PC0
*p_PortC_Mode_reg |= ( 1 << 4); //PC1
*p_PortC_Mode_reg |= (1 << 8); //PC2
*p_PortC_Mode_reg |= (1 << 12); //PC3
//----------------------------------------------------------------------
while(1)
{
// Make all rows as HIGH
*p_PortC_Out_reg |= (1); //PC0
*p_PortC_Out_reg |= (1 << 1); //PC1
*p_PortC_Out_reg |= (1 << 2); //PC2
*p_PortC_Out_reg |= (1 << 3); //PC3
//Make 1st row LOW (PC0)
*p_PortC_Out_reg &= (~1);
//Scan the columns
//check if 1st column (PA0) is LOW
if(!(*p_PortA_In_reg &= (1)))
{
//key '1' is pressed
delay();
printf("1\n");
}
//check if 2nd column (PA1) is LOW
if(!(*p_PortA_In_reg &= (1 << 1)))
{
//key '2' is pressed
delay();
printf("2\n");
}
//check if 3rd column (PA4) is LOW
if(!(*p_PortA_In_reg &= (1 << 4)))
{
//key '3' is pressed
delay();
printf("3\n");
}
// Make all rows as HIGH
*p_PortC_Out_reg |= (1); //PC0
*p_PortC_Out_reg |= (1 << 1); //PC1
*p_PortC_Out_reg |= (1 << 2); //PC2
*p_PortC_Out_reg |= (1 << 3); //PC3
//Make 2nd row LOW (PC1)
*p_PortC_Out_reg &= (~(1 << 1));
//Scan the columns
//check if 1st column (PA0) is LOW
if(!(*p_PortA_In_reg &= (1)))
{
//key '4' is pressed
delay();
printf("4\n");
}
//check if 2nd column (PA1) is LOW
if(!(*p_PortA_In_reg &= (1 << 1)))
{
//key '5' is pressed
delay();
printf("5\n");
}
//check if 3rd column (PA4) is LOW
if(!(*p_PortA_In_reg &= (1 << 4)))
{
//key '6' is pressed
delay();
printf("6\n");
}
// Make all rows as HIGH
*p_PortC_Out_reg |= (1); //PC0
*p_PortC_Out_reg |= (1 << 1); //PC1
*p_PortC_Out_reg |= (1 << 2); //PC2
*p_PortC_Out_reg |= (1 << 3); //PC3
//Make 3rd row LOW (PC2)
*p_PortC_Out_reg &= (~(1 << 2));
//Scan the columns
//check if 1st column (PA0) is LOW
if(!(*p_PortA_In_reg &= (1)))
{
//key '7' is pressed
delay();
printf("7\n");
}
//check if 2nd column (PA1) is LOW
if(!(*p_PortA_In_reg &= (1 << 1)))
{
//key '8' is pressed
delay();
printf("8\n");
}
//check if 3rd column (PA4) is LOW
if(!(*p_PortA_In_reg &= (1 << 4)))
{
//key '9' is pressed
delay();
printf("9\n");
}
// Make all rows as HIGH
*p_PortC_Out_reg |= (1); //PC0
*p_PortC_Out_reg |= (1 << 1); //PC1
*p_PortC_Out_reg |= (1 << 2); //PC2
*p_PortC_Out_reg |= (1 << 3); //PC3
//Make 4th row LOW (PC3)
*p_PortC_Out_reg &= (~(1 << 3));
//Scan the columns
//check if 1st column (PA0) is LOW
if(!(*p_PortA_In_reg &= (1)))
{
//key '*' is pressed
delay();
printf("*\n");
}
//check if 2nd column (PA1) is LOW
if(!(*p_PortA_In_reg &= (1 << 1)))
{
//key '0' is pressed
delay();
printf("0\n");
}
//check if 3rd column (PA4) is LOW
if(!(*p_PortA_In_reg &= (1 << 4)))
{
//key '#' is pressed
delay();
printf("#\n");
}
} // end of 'while' loop
}
And here I paste needed fragment from MCU Reference Manual (except for Memory Addresses, because that's in code comments at the beginning):
While debugging a code line by line I noticed that, when theres's a beginning of a while(1){..} loop, where are first 2 lines of *p_PortC_Out_reg |=... (for PC0 and PC1), except for *p_PortC_Out_reg, alos are being changed values of *p_PortA_In_reg () and I have no idea why is that and I thought if that's the source of a problem? I double checked if I connected all connectors the right way, so that's not an issue. I'm also not sure if I correctly used Input/Output Modes (Pull-up/Pull-down I mean) and I would be very greatful If any of You would have a look on that, because after several hours I'm out of ideas what's wrong and how to fix it.