I was wondering was 0xff, 0x00, and 0x0f represent. TRISA, TRISB, and TRISC are the ports being used on my board.
void main()
{
TRISA = 0xff;
TRISB = 0x00;
TRISC = 0x00;
ADCON1 = 0x0f;
}
TRISA is the tristate controller bits for I/O line A. This turns on or off the tristate gates that select whether the output register powers the pins or not. With the tristates off, the pins are input pins.
I'm not absolutely sure since I haven't checked the manual in over 10 years but I think 0xFF turns on all the tristates, so all the pins are input pins. I could have it backwards though.
Related
I am trying to write a program that will enable me to send data from my TI microcontroller to the very common HD4478 LCD. Rather than utilizing a parallel pin setup, I thought it would be a good idea to try and use a serial setup, so the LCD has a PCF8574T I2C I/O expander backpack. I am fairly new to writing embedded programs, and this is my first time using any real serial wiring communication protocols (I2C/SPI) so I'm struggling a bit to get this to work. Before I explain my confusion, here are the datasheets for the 3 respective components:
Microcontroller Data Sheet: https://www.ti.com/lit/ds/symlink/tm4c123gh6pm.pdf
LCD data sheet: https://circuitdigest.com/sites/default/files/HD44...
I/O Expander Data Sheet: https://www.nxp.com/docs/en/data-sheet/PCF8574_PCF...
My main problem is, I have no real idea what I'm doing wrong, but I am assuming it's something with the way I am initializing the LCD to 4-bit mode. I am a bit confused by this initialization walkthrough on the LCD data sheet:
And then This latter explanation that further explains how to initialize it to 4 bit mode, which is what I'll be using with my I/O expander:
I don't think I quite grasp whether to send the initial function set Command to 4-bit mode in 8-bit mode or 4-bit mode, and when the exact changeover to 4-bit mode occurs in the initialization process.
The way I transfer data over the data line is the 4-bit mode, so I am sending the upper nibble. and then lower nibble. This goes for both data bytes and command bytes. Below is my code. Currently flashing it and running simply has no effect on the LCD. I know that I am operating at the correct slave address since I do not get any flags present after the initial slave address transmit that would indicate any error. However, all of my commands in I2C_LCD_Enable and the latter command in main() that attempts to send a singular character to the LCD have no effect as well.
#include "TM4C123.h" // Device header
#include "RTE_Components.h" // Component selection
//data pin should be open drain in i2c modules
#define DATA 1
#define COMMAND 0
//I can think of each Pin connected to command/control as a singular bit
void GPIOE_enable(void);
void I2C_enable(void);
void I2C_LCD_enable(void);
void I2C_transfer_byte(char byte,int mode);
void delay_50_ms(void);
uint32_t address_transfer_value;
uint32_t data_value;
#define E 0x04 //bit 2
int main(){
GPIOE_enable();
I2C_enable();
I2C_LCD_enable();
I2C_transfer_byte(0x01,COMMAND);
I2C_transfer_byte(0x80,COMMAND); //set cursor to first row
delay_50_ms();
I2C_transfer_byte('a',DATA);
}
//port E, pins pe4 and pe5, have the alternative function as acting the clock/data lines for I2C module 2
void GPIOE_enable(void){
SYSCTL->RCGCGPIO |= 0x10; //enable port E
GPIOE->DIR |= 0x10 | 0x20;
GPIOE->DEN |= 0x10 | 0x20; //enable pins pe4 and pe5
GPIOE->AFSEL = 0x10 | 0x20; //enable pins Pe4 and Pe5 for their alternate function
GPIOE->ODR |= 0x20; //pe5 is data pin, must be set to open drain
GPIOE->PCTL |= (3 << 16) | (3 << 20);
}
void I2C_enable(void){
SYSCTL->RCGCI2C |= 0x04;
I2C2->MCR |= 0x10; //initialize I2C master
GPIOE->PUR |= 0x10 | 0x20; //I pulled up the Clock and Data Lines because they were low: Not pulling them up won't allow them to transfer from their high to low states when transmission begins and the I2C->MCS & 0x01 condition hangs forever
I2C2->MTPR = 0x09; //see data sheet: This initializes SCL speed to 100k kbps
I2C2->MSA = (0x27 << 1); //see data sheet: This sets slave address and sets mode to TRANSMIT
I2C2->MCS |= 0x07;
while (I2C2->MCS & 0x01);
}
//HD775 data sheet explains the initialization process on pages 24 and 42
void I2C_LCD_enable(void){
//not sure how to initialize quite yet...
/*I2C2->MDR = 0x28; //this initializes 4-bit mode. This command, AND THIS COMMAND ONLY, takes only one write since it's still in 8-bit mode
I2C2->MCS |= 0x07;
while (I2C2->MCS & 0x01);
delay_50_ms();
I2C2->MDR = (1 << E); //set ENABLE to high
I2C2->MCS |= 0x07;
while (I2C2->MCS & 0x01);
delay_50_ms();
I2C2->MDR = ~(1<<E); //set ENABLE to low
I2C2->MCS |= 0x07;
while (I2C2->MCS & 0x01);
delay_50_ms();*/
I2C_transfer_byte(0x28,COMMAND);
I2C_transfer_byte(0x06,COMMAND); //Move cursor right
I2C_transfer_byte(0x01,COMMAND); //clear screen
I2C_transfer_byte(0x0F,COMMAND); //turn display on
}
//the upper 4 bits are the data pins : D4, D5, D6, D7 (bits 0-3)
//the lower 3 bits are: RS, RW, E
//to send a command, we should set RS to 0 to select "Command Mode" on LCD
//if mode is 0, or COMMAND, do a logical OR with 0, which will set RS, bit 0, to 0
//if mode is 1, or DATA, do a logical or with 1, so RS, bit 0, is set to 1
//we also need to pulse E, or enable to make sure any of these data/commands actually are executed
//The E pin corresponds to bit 2, so I'll send each data byte with first E enabled, and then E set to to low, to pulse Enable
//send upper nibble, pulse enable, send lower nibble, pulse enable
void I2C_transfer_byte(char byte,int mode){
char byte_shifted;
char byte_upper_nibble;
char byte_lower_nibble;
byte_shifted = byte << 4;
byte_upper_nibble = byte & 0xF0;
I2C2->MDR = (mode | (I2C2->MDR & 0xF0)| byte_upper_nibble) | E; //set command to be most significant bit, and enable E
I2C2->MCS |= 0x07;
while (I2C2->MCS & 0x01){
data_value = I2C2->MBMON;
}
delay_50_ms();
I2C2->MDR = (mode | (I2C2->MDR & 0xF0)| byte_upper_nibble) & ~E; //set command to be most significant bit, and disable E (pulsing E enables the command/data)
I2C2->MCS |= 0x07;
while (I2C2->MCS & 0x01);
delay_50_ms();
byte_lower_nibble = byte_shifted & 0xF0;
I2C2->MDR = (mode | (I2C2->MDR & 0x0F) | byte_lower_nibble) | E;
I2C2->MCS |= 0x07;
while (I2C2->MCS & 0x01);
delay_50_ms();
I2C2->MDR = (mode | (I2C2->MDR & 0x0F) | byte_lower_nibble) & ~E;
I2C2->MCS |= 0x07;
while (I2C2->MCS & 0x01);
delay_50_ms();
}
//clock frequency is 1,000,000 cycles/second
void delay_50_ms(void){
SYSCTL->RCGCTIMER |= 0x01;
TIMER0->CTL = 0;
TIMER0->CFG |= 0x04;
TIMER0->TAMR |= 0x01 | 0x10; //single shot mode, enable interrupt
TIMER0->TAILR = 20000; //1,000,000 / 20,0000 = 50
TIMER0->CTL = 0x01;
while ((TIMER0->RIS & 0x01) == 0);
}
I am using the on-board 3.3V power supply from the TI board as my VCC supply.
I think before discussing that the LCD is not working properly, I want to know whether I2C is working properly and whether the Address PIN define.
The address pin of I/O Expander IC is all connected to HIGH, so your Slave address is 0x27
(I just want to make sure whether this part is okay because if there is a problem, there will be problems in the subsequent tests)
If I2C communication work normally, the I/O Expander IC control should be correct.
( Send some commands to see if the IC outputs according to your commands)
If the I/O expander IC work abnormally, maybe you can check the I2C signal use a logic analyzer or oscilloscope to check whether the I2C signal of the MCU is correct. (Slave Address, ACK...etc)
If the above of them is correct, we can start to check the LCD part!
Reminder: Your hyperlink is failed for the LCD and I/O Expander IC Data Sheet.
For the part of Initializing by internal reset circuit
It means that when you supply power to the LCD, it will perform the actions 1~4 below.
During this period, you can use an oscilloscope or logic analyzer to measure the BF pin. It should be HIGH, always When your VCC rises to 4.5V, BF will continue for another 10ms before pulling LOW.
But if VCC does not rise to 4.5V, it must be initialized through MPU.
I saw at the end of the article
I am using the on-board 3.3V power supply from the TI board as my VCC
supply.
Does your LCD use 3.3V as the power supply? If yes, you shall initialize LCD by MPU.
(But I suggest using the 5V to supply that can reduce the debug time.)
If using the internal initialize function, the LCD setting shall be like below:
8-bit interface
1-line display
5x8 dot character font
So if you want to change to 4-bit mode, need to use the Function set Instruction to set again. (Datasheet P.28)
The signal transmission part must be tested according to the timing diagram
It takes 4 steps to send a command
Transfer upper 4-bit data.
Busy flag check (BF=1)
Busy flag check (BF=0)
Transfer lower 4-bit data
Use the Example of the HD44780U Datasheet for testing (Datasheet P.42)
Step 6, need to be divided into 2 times to send.
And it will show the 'H' on the LCD.
I could find a problem related to NVIC_Init in STM32F10x library related to priorities to handle nested interrupts.
We know that any interrupt with a priority value equal or higher than BASEPRI ( 11 in our case) can call FromISR() FreeRTOS API functions.
FreeRTOS uses 15 level ( the lowest priority).
#define configLIBRARY_KERNEL_INTERRUPT_PRIORITY 15
In other words, FreeRTOS allows us to call API fuctions ( see xQueueSendToBackFromISR) from ISR with 15-11 priority.
When we initialize the NVIC we use level #11
#define WRTU2_DMA1_SPI2_IRQ_PRIORITY (configLIBRARY_KERNEL_INTERRUPT_PRIORITY-4*)
/* DMA1 Channel4 interrupt setting */
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel4_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = WRTU2_DMA1_SPI2_IRQ_PRIORITY;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = WRTU2_DMA1_SPI2_IRQ_PRIORITY;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
So, we should be OK. But the problem exists. I decided to check NVIC_Init.
According to the information from STM32 datasheet the priority register is 0xe000e40e ( NVIC channel 14 belongs to DMA1_Channel4 interrupts).
And I could read 0x00 from that register after NVIC was initialized. It means NVIC channel #14 has the highest priority in the system.
And it causes all problems.
I added the simplest fix NVIC->IP[DMA1_Channel4_IRQn] = 0xF0;
And the system does not fail anymore. So, our current problem is solved.
Of course, I tried to analyze what happens in NVIC_Init
**
* #brief Initializes the NVIC peripheral according to the specified
* parameters in the NVIC_InitStruct.
* #param NVIC_InitStruct: pointer to a NVIC_InitTypeDef structure that contains
* the configuration information for the specified NVIC peripheral.
* #retval None
*/
void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct)
{
uint32_t tmppriority = 0x00, tmppre = 0x00, tmpsub = 0x0F;
/* Check the parameters */
assert_param(IS_FUNCTIONAL_STATE(NVIC_InitStruct->NVIC_IRQChannelCmd));
assert_param(IS_NVIC_PREEMPTION_PRIORITY(NVIC_InitStruct->NVIC_IRQChannelPreemptionPriority));
assert_param(IS_NVIC_SUB_PRIORITY(NVIC_InitStruct->NVIC_IRQChannelSubPriority));
if (NVIC_InitStruct->NVIC_IRQChannelCmd != DISABLE)
{
/* Compute the Corresponding IRQ Priority --------------------------------*/
tmppriority = (0x700 - ((SCB->AIRCR) & (uint32_t)0x700))>> 0x08;
tmppre = (0x4 - tmppriority);
tmpsub = tmpsub >> tmppriority;
tmppriority = (uint32_t)NVIC_InitStruct->NVIC_IRQChannelPreemptionPriority << tmppre;
tmppriority |= NVIC_InitStruct->NVIC_IRQChannelSubPriority & tmpsub;
tmppriority = tmppriority << 0x04;
NVIC->IP[NVIC_InitStruct->NVIC_IRQChannel] = tmppriority;
/* Enable the Selected IRQ Channels --------------------------------------*/
NVIC->ISER[NVIC_InitStruct->NVIC_IRQChannel >> 0x05] =
(uint32_t)0x01 << (NVIC_InitStruct->NVIC_IRQChannel & (uint8_t)0x1F);
}
else
{
/* Disable the Selected IRQ Channels -------------------------------------*/
NVIC->ICER[NVIC_InitStruct->NVIC_IRQChannel >> 0x05] =
(uint32_t)0x01 << (NVIC_InitStruct->NVIC_IRQChannel & (uint8_t)0x1F);
}
}
So, I added the similar test code to my application to see how it converts all values
uint32_t NVIC_IRQChannelPreemptionPriority=0xFF,NVIC_IRQChannelSubPriority=0xFF;
int32_t tmppriority = 0x00, tmppre = 0x00, tmpsub = 0x0F;
tprintf("\n\rSCB->AIRCR=0x%08x",SCB->AIRCR);
tmppriority = (0x700 - ((SCB->AIRCR) & (uint32_t)0x700))>> 0x08;
tprintf("\n\rtmppriority=0x%08x",tmppriority);
tmppre = (0x4 - tmppriority);
tmpsub = tmpsub >> tmppriority;
tprintf("\n\rtmppre=0x%08x",tmppre);
tprintf("\n\rtmpsub=0x%08x",tmpsub);
tmppriority = (uint32_t)NVIC_IRQChannelPreemptionPriority << tmppre;
tmppriority |= NVIC_IRQChannelSubPriority & tmpsub;
tmppriority = tmppriority << 0x04;
tprintf("\n\rtmppriority=0x%08x",tmppriority);
There is a log
SCB->AIRCR=0xfa050000
tmppriority=0x00000007
tmppre=0xfffffffd
tmpsub=0x00000000
tmppriority=0x00000000
Note, even I specify 0xFF for both input parameters it returns 0x00.
I am really surprised about that behavior. This is a library function.
People use it for many years. So, I am really confused I can find find the problem in that function.
Maybe it is related to Application interrupt and reset control register (SCB_AIRCR)
Address offset: 0x0C
Reset value: 0xFA05 0000
Required privilege: Privileged
The AIRCR provides priority grouping control for the exception model, endian status for data
accesses, and reset control of the system.
Note, in the library sources I can see #define AIRCR_VECTKEY_MASK ((uint32_t)0x05FA0000)
So, it looks like we have some kind of BIG vs LITTLE ENDIAN byte order in the 16-bit nibble.
Do you have any suggestion or knowledge about the problem?
I found the problem, the problem is I should use NVIC_SetPriorityGrouping(3); as 3 for the cortex-m3.
then it provides 4-bit preemptive priority and 0 bit for subpriority. At final when I initiliase like that it works as I expected.
/* DMA1 Channel4 interrupt setting */
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel4_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 11;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
I'm trying to run this code on TIVA C board. sw2 connected to PF0, sw1 connected to PF4 and RGB LED connected to PF1, PF2 and PF3.
When I press sw2 it shall turn the led blue and if sw1 is pressed it shall turn the led green otherwise it shall be red.
The code doesn't function properly. I hope you can point out what I did wrong.
/*************************
PORT F Addresses
*************************/
#define RCGCGPIO (*((volatile unsigned long*)0x400FE608)) //CLOCK
#define PORTFDATA (*((volatile unsigned long*)0x400253FC)) //DATA
#define PORTFDIR (*((volatile unsigned long*)0x40025400)) //DIRECTION
#define PORTFDEN (*((volatile unsigned long*)0x4002551C)) //ENABLE
#define PORTFLOCK (*((volatile unsigned long*)0x40025520)) //LOCK (lock or unlocks PF0)
#define PORTFCR (*((volatile unsigned long*)0x40025524)) //COMMIT (uncommit PF0)
#define PORTFPUR (*((volatile unsigned long*)0x40025510)) // PULL UP resistor
#define PORTFPDR (*((volatile unsigned long*)0x40025514)) // PULL Down resistor
/*************************/
int sw1;
int sw2;
int delay;
int main (void)
{
RCGCGPIO = 0x20; //Enable clock for PORT F
delay = RCGCGPIO;
PORTFLOCK = 0x4C4F434B; // unlock commit reg
PORTFCR = 0x01; // unlock PF0
PORTFDEN = 0x1F; //Enable pins 0 to 4
PORTFDIR = 0x0E; // pins 0 and 4 input - pins 1,2,3 output
PORTFPUR = 0x11;
while (1)
{
sw2 = PORTFDATA & 0x00000001;
sw1 = PORTFDATA & 0x00000010;
if (sw1 == 1)
PORTFDATA |= 0x00000002;
else if (sw2 == 1)
PORTFDATA |= 0x00000004;
else
PORTFDATA |= 0x00000008;
}
}
Here are two obvious problems with your code. There are probably more...
You set sw1 = PORTFDATA & 0x00000010, so the only possible values sw1 can have are 0x10 or 0x00. Then you test if (sw1 == 1). But this test will never be true because sw1 can never equal 1.
You use the |= operator to set the bits of PORTFDATA. But nowhere do you ever clear the bits of PORTFDATA. So your LEDs may turn on but they will never turn off.
Have you tried the sample code comming with CCS to make sure that hardware are functional?
The sample code uses TI library instead of plain register Read & Write, however you can dig out the acutal register by go to defination. Anyway, I'm a bit curious about why you use plain register in the first place instead of TI library? ARM MCU is not 8051 anymore.
A couple of things to keep in mind:
The launchpad buttons are negative logic, so if your switch1== 0x01, it is NOT being pressed.
Try something like:
If
sw1 == 0x01 //switch not pressed
PORTFDATA &= ~(0x0E); //ledz off
else
PORTFDATA ^= 0x02; //toggle red
I am also learning ARM & C solely self-study, so I feel your pain. It took many hours of toggling single leds with bitwise operators just to fathom what is going on. Stick with it!!!
/e
I am trying to read/write on MicroSD card by program SPI. By oscilloscope I see that CS and MOSI and CLK are working correct.
By "correct" I mean that CS is up, but when I send CMD it is low, then up again; MOSI send CMD correctly, a bit before first CLK and at this time in MISO I try to catch something; CLK: it makes clocks about 4 uS between fronts.
I am sending 10 x 0xFF above CMD0, and I am doing this after any CMD.
I send:
SPI_send(CMD0, (unsigned long) 0x00, 0x95);
SPI_send(CMD8, (unsigned long) 0x01AA, 0x87);
SPI_send(CMD58, (unsigned long) 0x00, 0x01);
But all what I see is 1 on MISO.
It happends only if MicroSD card IS in cardreader. If it is not, MISO is always 1.
MicroSD Cards I try are 2 and 4 Gb. May be it is meanfull. They works if I connect them to my PC.
If it'll help, I will write my code here to write byte
for(int bit = 0; bit < 8; bit++)
{
if (byte & 0x80)
PORTG |=SPI_MOSI;
else
PORTG &= ~SPI_MOSI;
PORTG |= SPI_CLK;
byte |= (PINE & SPI_MISO)>>6;
byte <<= 1;
PORTG &= ~SPI_CLK;
}
Thanks for ur help!
The following code won't set any of the pins high on my PIC18F14K50, yet it couldn't be simpler!
#include <pic18.h>
#include <htc.h>
void main(void)
{
// Set ALL pins to output:
TRISA = 0;
TRISB = 0;
TRISC = 0;
// Set ALL pins to high:
LATA = 0b11111111;
LATB = 0b11111111;
LATC = 0b11111111;
// Leave pins high and wait forever:
while (1);
}
I'm using MPLAB v8.43 and the Hi-Tech ANSI C Compiler.
A logic probe shows none of the pins high except the VUSB and the MCLR.
Any ideas?
At least some of the pins may be configured as Analog Inputs.
From the Datasheet for this device
The operation of pin RA4 as analog is selected by setting the ANS3
bit in the ANSEL register which is the default set-ting after a
Power-on Reset.
If you do not set the ANSEL register the pin cannot be used as output as it is configured as an analog input.
This applies to all the pins that can be A/D inputs, which does not cover all the pins you have.
Then again I do not see any configuration bit setup in your code. That device e.g. has 2 different instruction sets and you have to at the very least specify which instruction set you are using in the configuration bits.
You may try adding this to the top of your code just after the includes :
// Configuration BITS setup
__CONFIG(1, FOSC_INTIO2 & XINST_OFF);
__CONFIG(2, WDTEN_OFF & PWRTEN_ON);
__CONFIG(3, MCLRE_OFF);
I suppose that you didn't configure the MCPU oscillator, try to define:
; Oscillator:
config FOSC = INTIO2 ;Internal RC oscillator
;
; PLL x4 Enable bit:
config PLLCFG = OFF
and
;Define oscillator frequency
;{
movlw b'01100000'
movwf OSCCON
movlw b'01000000'
movwf OSCTUNE
;};
This directives are for MPLAB asm and not for Hi-Tech, but file registers should have the same names.