I'm trying to make the PF0 and PF4 leds blink while the switches are pressed. But it simply does not turn on any leds.
I was told I needed to use two ports, I don't see why, since this can be done with only one port — in this case the port D — but it was suggested that I use the port K as well (?).
The board is a Tiva C TM4c1294nctpd
#include <stdint.h>
#include <stdbool.h>
#include "inc/hw_memmap.h"
#include "driverlib/debug.h"
#include "driverlib/gpio.h"
#include "driverlib/sysctl.h"
#include <inc/tm4c1294ncpdt.h>
uint32_t SW1,SW2; //
int main(void) {
while(1){
SYSCTL_RCGCGPIO_R=0X1100; // Enable port D
GPIO_PORTD_DIR_R=0X03; //enable the GPIO pin PN0,
GPIO_PORTD_DEN_R=0X03;
GPIO_PORTK_AHB_DIR_R=0;
GPIO_PORTK_AHB_DEN_R=0X03;
GPIO_PORTK_AHB_PUR_R=0X01;
SW1 = GPIO_PORTD_DATA_R&0x10; // read PF4 into SW1
SW2 = GPIO_PORTD_DATA_R&0x01; // read PF0 into SW2
if (!SW1 && !SW2) { // both pressed
GPIO_PORTD_DATA_R = 0x04;
} else if (!SW1) { // SW1 pressed
GPIO_PORTD_DATA_R = 0x02;
} else if (!SW2) { // SW2 pressed
GPIO_PORTD_DATA_R = 0x08;
} else { // neither
GPIO_PORTD_DATA_R = 0x00;
}
}
}
You have only enabled D0 and D1, but appear to be using D0, D1, D2, D3 and D4.
You have set D0 and D1 as output, but appear to be be using D1, D2, D3 as outputs.
You have set D0 as an output, but attempt to read it as an input.
The configuration of PORTK is entirely irrelevant if you are not using it.
The RCGCGPIO enables the clock for PORTN and PORTJ which you are not using at all.
I am not familiar with the part and have only briefly read the data sheet, but the the PORTD clock, direction and digital enable configuration should be as follows if the input/output code is itself correct.
SYSCTL_RCGCGPIO_R = 0x0008; // Enable port D clock
GPIO_PORTD_DIR_R = 0x0E; // D4, D0 input, D1 to D3 output.
GPIO_PORTD_DEN_R = 0x1F; // Enable D0 to D4
These initialisation settings need be done once only - before the loop, not inside it.
int main(void)
{
SYSCTL_RCGCGPIO_R = 0x0008; // Enable port D
GPIO_PORTD_DIR_R = 0x0E; // D4, D0 input, D1 to D3 output.
GPIO_PORTD_DEN_R = 0x1F; // Enable D0 to D4
for(;;)
{
uint32_t SW1 = GPIO_PORTD_DATA_R & 0x10; // read PD4 into SW1
uint32_t SW2 = GPIO_PORTD_DATA_R & 0x01; // read PD0 into SW2
if (!SW1 && !SW2) // both pressed
{
GPIO_PORTD_DATA_R = 0x04;
}
else if (!SW1) // SW1 pressed
{
GPIO_PORTD_DATA_R = 0x02;
}
else if (!SW2) // SW2 pressed
{
GPIO_PORTD_DATA_R = 0x08;
}
else // neither
{
GPIO_PORTD_DATA_R = 0x00;
}
}
}
After thought:
The comments in the presumably copy & pasted code suggest the board might be an EK-TM4C1294XL. In that case the the LEDs are called D1, D2, D3, D4 (D for diode, not _PORTD), but are on GPIOs PN1, PN0, PF4 and PF0 respectively, and the switches are on PJ0 and PJ1.
In that case perhaps the following will be more successful:
int main(void)
{
SYSCTL_RCGCGPIO_R |= (1<<5 | 1<<8 | 1<<12); // Enable port F, J and N clocks
GPIO_PORTN_DIR_R |= 0x03; // PN1 = LED0, PN0 = LED1 (Outputs)
GPIO_PORTN_DEN_R |= 0x03; // Enable PN0 and PN1
GPIO_PORTF_DIR_R |= 0x11; // PF4 = LED3, PF0 = LED4 (Outputs)
GPIO_PORTF_DEN_R |= 0x11; // Enable PF0 and PF4
GPIO_PORTJ_DIR_R &= ~0x03; // PJ0 = SW1, PJ1 = SW2 (Inputs)
GPIO_PORTJ_DEN_R &= ~0x03; // Enable PJ0 and PJ4
for(;;)
{
uint32_t SW1 = GPIO_PORTJ_DATA_R & 0x01; // read PJ0 into SW1
uint32_t SW2 = GPIO_PORTJ_DATA_R & 0x02; // read PJ1 into SW2
if (!SW1 && !SW2) // both pressed
{
GPIO_PORTF_DATA_R = 0x01; // LED4
}
else if (!SW1) // SW1 pressed
{
GPIO_PORTF_DATA_R = 0x10; // LED3
}
else if (!SW2) // SW2 pressed
{
GPIO_PORTN_DATA_R = 0x01; // LED2
}
else // neither
{
GPIO_PORTN_DATA_R = 0x02; // LED1
}
}
}
This remains broken because the code only ever switches LED's on - an it does not respect other hardware that may be connected to other pins on ports F and N; you need to add code to read-modify-write the respective pins fo reach LED you set, you need to clear the other three. I'll leave that to you - it goes beyond the original question.
Related
I'm Noh.
I'm trying to control Microcontroller with C code.
And I'm using a code I got from GitHub. (Here's the link https://github.com/jwr/msp430_usi_i2c)
I encountered the problem that main function doesn't stop.
Even though there's no loop command in main, command flow repeats again and again.
I write command flow like below.
Write 00 → Write AF → Write 00 → Write 05 → Write 45 → Write 40 → Write 03 → Write B0 → Read EE
And you can see the command flow repeats from beginning to end.
Please refer to below code and the communication result.
#include <msp430.h>
#include <stdint.h>
#include "usi_i2c.h"
#include <stdio.h>
#include <stdlib.h>
// Internal state
static uint16_t const *i2c_sequence;
static uint16_t i2c_sequence_length;
static uint8_t *i2c_receive_buffer;
static uint16_t i2c_wakeup_sr_bits;
i2c_state_type i2c_state = I2C_IDLE;
static uint8_t status;
static inline void i2c_prepare_stop();
static inline void i2c_prepare_data_xmit_recv();
void i2c_send_sequence(uint16_t const * sequence,
uint16_t sequence_length,
uint8_t *received_data,
uint16_t wakeup_sr_bits) {
while(i2c_state != I2C_IDLE); // we can't start another sequence until the current one is done
while((status==0xEE)|(status==0xEF)) P1OUT |= 0x01;
P1OUT &= ~0x01;
i2c_sequence = sequence;
i2c_sequence_length = sequence_length;
i2c_receive_buffer = received_data;
i2c_wakeup_sr_bits = wakeup_sr_bits;
i2c_state = I2C_START;
USICTL1 |= USIIFG; // actually start communication
}
static inline void i2c_prepare_stop() {
USICTL0 |= USIOE; // SDA = output
USISRL = 0x00;
USICNT |= 0x01; // Bit counter= 1, SCL high, SDA low
i2c_state = I2C_STOP;
}
static inline void i2c_prepare_data_xmit_recv() {
if(i2c_sequence_length == 0) {
i2c_prepare_stop(); // nothing more to do, prepare to send STOP
} else {
if(*i2c_sequence == I2C_RESTART) {
USICTL0 |= USIOE; // SDA = output
USISRL = 0xff; // prepare and send a dummy bit, so that SDA is high
USICNT = (USICNT & 0xE0) | 1;
i2c_state = I2C_START;
}
else if(*i2c_sequence == I2C_READ) {
USICTL0 &= ~USIOE; // SDA = input
USICNT = (USICNT & 0xE0) | 8; // Bit counter = 8, RX data
i2c_state = I2C_RECEIVED_DATA; // next state: Test data and ACK/NACK
} else { // a write
(*i2c_sequence >> 8) == 0
USICTL0 |= USIOE; // SDA = output
USISRL = (char)(*i2c_sequence); // Load data byte
USICNT = (USICNT & 0xE0) | 8; // Bit counter = 8, start TX
i2c_state = I2C_PREPARE_ACKNACK; // next state: prepare to receive data ACK/NACK
}
i2c_sequence++;
i2c_sequence_length--;
}
}
#ifdef __GNUC__
__attribute__((interrupt(USI_VECTOR)))
#else
#pragma vector = USI_VECTOR
__interrupt
#endif
void USI_TXRX(void)
{
switch(__even_in_range(i2c_state,12)) {
case I2C_IDLE:
break;
case I2C_START: // generate start condition
USISRL = 0x00;
USICTL0 |= (USIGE|USIOE);
USICTL0 &= ~USIGE;
i2c_prepare_data_xmit_recv();
break;
case I2C_PREPARE_ACKNACK: // prepare to receive ACK/NACK
USICTL0 &= ~USIOE; // SDA = input
USICNT |= 0x01; // Bit counter=1, receive (N)Ack bit into USISRL
i2c_state = I2C_HANDLE_RXTX; // Go to next state: check ACK/NACK and
continue xmitting/receiving if necessary
break;
case I2C_HANDLE_RXTX: // Process Address Ack/Nack & handle data TX
if((USISRL & BIT0) != 0) { // did we get a NACK?
i2c_prepare_stop();
} else {
i2c_prepare_data_xmit_recv();
}
break;
case I2C_RECEIVED_DATA: // received data, send ACK/NACK
*i2c_receive_buffer = USISRL;
i2c_receive_buffer++;
USICTL0 |= USIOE; // SDA = output
if(i2c_sequence_length > 0) {
// If this is not the last byte
USISRL = 0x00; // ACK
i2c_state = I2C_HANDLE_RXTX; // Go to next state: data/rcv again
} else { // last byte: send NACK
USISRL = 0xff; // NACK
i2c_state = I2C_PREPARE_STOP; // stop condition is next
}
USICNT |= 0x01; // Bit counter = 1, send ACK/NACK bit
break;
case I2C_PREPARE_STOP: // prepare stop condition
i2c_prepare_stop(); // prepare stop, go to state 14 next
break;
case I2C_STOP: // Generate Stop Condition
USISRL = 0x0FF; // USISRL = 1 to release SDA
USICTL0 |= USIGE; // Transparent latch enabled
USICTL0 &= ~(USIGE|USIOE); // Latch/SDA output disabled
i2c_state = I2C_IDLE; // Reset state machine for next xmt
if(i2c_wakeup_sr_bits) {
_bic_SR_register_on_exit(i2c_wakeup_sr_bits); // exit active if prompted to
}
break;
}
USICTL1 &= ~USIIFG; // Clear pending flag
}
void main(){
i2c_init(USIDIV_5, USISSEL_2);
uint16_t PUP[] = {0xEA, 0x00};
uint16_t PDWN[] = {0xEA, 0x20};
uint16_t CVOL_PowerUp[] = {0xEA, 0xAF, 0x00};
uint16_t AMODE_PowerUp[] = {0xEA, 0x05, 0x45};
uint16_t AMODE_PowerDown[] = {0xEA, 0x05, 0x41};
uint16_t RDSTAT_Command[] = {0xEA, 0xB0};
uint16_t RDSTAT_Read[] = {0xEB, I2C_READ};
uint16_t START[] = {0xEA, 0x51};
uint16_t PLAY[] = {0xEA, 0x40, 0x03};
uint16_t STOP[] = {0xEA, 0x61};
i2c_send_sequence(PUP, 2, &status, LPM0_bits); // 00
i2c_send_sequence(CVOL_PowerUp, 3, &status, LPM0_bits); // AF 00
i2c_send_sequence(AMODE_PowerUp, 3, &status, LPM0_bits); // 05 45
i2c_send_sequence(PLAY, 3, &status, LPM0_bits); // 40 03
i2c_send_sequence(RDSTAT_Command, 2, &status, LPM0_bits); // B0
i2c_send_sequence(RDSTAT_Read, 2, &status, LPM0_bits);
}
void i2c_init(uint16_t usi_clock_divider, uint16_t usi_clock_source) {
_disable_interrupts();
USICTL0 = USIPE6|USIPE7|USIMST|USISWRST; // Port & USI mode setup
USICTL1 = USII2C|USIIE; // Enable I2C mode & USI interrupt
USICKCTL = usi_clock_divider | usi_clock_source | USICKPL;
USICNT |= USIIFGCC; // Disable automatic clear control
USICTL0 &= ~USISWRST; // Enable USI
USICTL1 &= ~USIIFG; // Clear pending flag
_enable_interrupts();
P1OUT = 0xC0; // P1.6 & P1.7 Pullups, others to 0
P1REN |= 0xC0; // P1.6 & P1.7 Pullups
P1DIR = 0xFF; // Unused pins as outputs
P2OUT = 0;
P2DIR = 0xFF;
}
This is code run result gotten by using Beagle(communication data recorder), and I believe you can see command flow is repeating (from 'Write 00' to 'Read EE')
I have no idea why main function repeats without any loop function.
I want this code run main function's command flow only once.
Do you happen to know why this happens and how to resolve this problem? 😥
Thank you!
Sincerely
Noh
Most programs for a microcontroller have some assembly language initialisation code that does some basic configuration of the MCU, copies the data section from flash to RAM, zeros the .bss, then jumps to main().
Typically, main() would never return. It would consist of an infinite loop, doing whatever tasks the software is meant to do, forever, until power is removed.
So your code returning is not very typical. What is the MCU meant to do if main() returns? It has nothing else to run. Some options for it might be to:
Spin doing nothing
Call main() again (in a loop)
Reset the MCU, which effectively restarts your code
It sounds like, in your case, either 2 or 3 is happening.
If you want your code to just stop after it has done its thing, add an empty infinite loop at the end of main():
for (;;)
;
#include <msp430.h>
#define BUTTON BIT3 // Port 1.3
#define REDLED BIT0 // Port 1.0
#define GRNLED BIT6 // Port 1.6
#define ZERO 0x08
#define ONE 0x48
#define TWO 0x09
#define THREE 0x49
int counter = 0;
int main(void) {
// Watchdog setup
WDTCTL = WDTPW + WDTHOLD; // stop watchdog (password + hold counter)
// LED initial setup
P1DIR |= REDLED + GRNLED; // set P1.0 and P1.6 as output (1) pins
P1OUT &= ~REDLED; // Disable REDLED
P1OUT &= ~GRNLED; // Disable GRNLED
// Button setup
P1DIR &= ~BUTTON; // button is an input
P1OUT |= BUTTON; // pull-up resistor
P1REN |= BUTTON; // resistor enabled
P1IE |= 0x08; //P1.3 interrupt enable
P1IES &= ~0x08; //lower edge
P1IFG &= ~0x08; //zero flag
while(1){
}
}
#pragma vector=PORT1_VECTOR
__interrupt void Port_1(void){
counter += 1;
counter = (counter % 4);
switch(counter){
case 0:
P1OUT = ZERO;
break;
case 1:
P1OUT = ONE;
break;
case 2:
P1OUT = TWO;
break;
case 3:
P1OUT = THREE;
break;
}
P1IFG &= ~0x08;
}
I can not enter the ınterrup routine .I checked interrup flag ,when I push the button flag will 1 but the leds are not change ,I think that I can not enter interrup.If I can , the led must be changed.What is the wrong ?
Global interrupts are disabled by default on program's startup. You need to add code that sets the global interrupt enable (GIE) bit at the end of main(). The most platform-independent (not really) way to do it is by calling __enable_interrupts() function.
#include <msp430.h>
#include <intrinsics.h>
...
__enable_interrupts();
Alternatively, set the GIE bit directly:
__bis_status_register(GIE);
To check whether interrupts are enabled (not that inside the interrupt handler they always will be disabled by default):
if (__get_SR_register() & GIE) {
printf("interrupts enabled\n");
} else {
printf("interrupts disabled\n");
}
I'm trying to turn the led on in my tiva launchpad(tm4c123).
Current code :
while (1)
{
switch(GPIO_PORTF_DATA_R & 0x11) // 0x11 = 10001
{
case 0x00: //both switches are pressed
{
GPIO_PORTF_DATA_R = 0x02; // turn on the red led
break;
}
case 0x01: //SW1 is pressed, SW2 is not pressed
{
GPIO_PORTF_DATA_R = 0x04; // turn on the blue led
break;
}
case 0x10: //SW2 is pressed, SW1 is not pressed
{
GPIO_PORTF_DATA_R = 0x08; // turn on the green led
break;
}
default:
GPIO_PORTF_DATA_R = 0;
break;
}
}
Without this two lines of code, this is what happens :
The board start with the green led on.
When I press both or only SW2 nothing happens.
When I press SW1 the red led turn on.
Could someone explain to me why?
GPIO_PORTF_LOCK_R = 0x4C4F434B;
GPIO_PORTF_CR_R = 0x1F;
You can read your switches on your tiva launchpad like this:
SW1 = GPIO_PORTF_DATA_R&0x10; // read PF4 into SW1
SW2 = GPIO_PORTF_DATA_R&0x01; // read PF0 into SW2
Then you can check the status of those inputs and make decisions.
if (!SW1 && !SW2) { // both pressed
GPIO_PORTF_DATA_R = 0x04;
} else if (!SW1) { // SW1 pressed
GPIO_PORTF_DATA_R = 0x02;
} else if (!SW2) { // SW2 pressed
GPIO_PORTF_DATA_R = 0x08;
} else { // neither
GPIO_PORTF_DATA_R = 0x00;
}
If you look at the TM4C123GH6PM datasheet, on page 205, it says;
Protection is provided for the GPIO pins that can be used as the four
JTAG/SWD pins
If you check the signal tables on page 1329, you will see that PF0 ,where one of your switches is connected to, is one of them. So you need to unlock it.
On page 684, it says
Writing 0x4C4F.434B to the GPIOLOCK register unlocks the GPIOCR
register.
The code works as follows:
Button pressed: green on, red off
Button ot pressed: green off, red on
All the code samples ive seen from people online had the pullup resistor enabled when using a button to toggle between the LEDs. Is this even necessary for a code to work?
I commented the line out in my code and the only change i noticed was that it turned one the reset button. Is that what its intended for?
#include <msp430g2553.h>
#define LED0 BIT0
#define LED1 BIT6
#define BUTTON BIT3
int main(void)
{
// Stop watchdog timer to prevent time out reset
WDTCTL = WDTPW + WDTHOLD;
P1DIR |= 0x40;
P1OUT &= ~0x40;
P1DIR |= 0x01;
P1OUT &= ~0x01;
P1DIR &= ~0x08;
P1SEL &= ~0x08;
//P1REN |= 0x08;
while (1) {
if ((P1IN & 0x08) == 0) {
P1OUT &= ~0x01;
P1OUT |= 0x40;
} else {
P1OUT |= 0x01;
P1OUT &= ~0x40;
}
}
return 0;
}
The code seems to work as intended but am wondering what this pullup resistor is actually intended to do?
Reset line is already pulled-up by external resistor, there is no need to pull it up with internal resistor. Reset pin also is not a GPIO (port) pin, so you basically can't enable internal pull-up for it. As for P1.3 button: some Launchpad board revisions have external pull-up resistor soldered for that button, some don't. So you should enable internal pullup for P1.3, just in case. When P1.3 button is not pressed, the circuit is open and you don't want P1.3 pin to be floating. Hence pull-up resistor required.
I found some old code of mine, it may be helpful for you. Especially pay attention to comments.
/* Program demonstrates interacting with buttons (GPIO Inputs) */
#include <msp430.h>
#define LED_RED_BIT BIT0
#define LED_GREEN_BIT BIT6
#define BUTTON_BIT BIT3
enum led_state {
RED_LIGHT = 0,
NO_LIGHT_R = 1, /* no light after red led turned off */
GREEN_LIGHT = 2,
NO_LIGHT_G = 3 /* no light after green led turned off */
};
enum led_state state; /* current state of LED state machine */
static unsigned char is_button_down;
static void init_leds(void)
{
P1DIR |= LED_GREEN_BIT | LED_RED_BIT;
P1OUT &= ~LED_GREEN_BIT;
P1OUT |= LED_RED_BIT;
state = RED_LIGHT;
}
static void init_button(void)
{
/* Since R34 is not installed -- turn on internal pull up for P1.3.
* Details: according to LaunchPad User's Guide, section 1.3:
* "Pullup resistor R34 and capacitor C24 on P1.3 removed to reduce
* the current consumption"
*/
P1OUT |= BUTTON_BIT; /* the pin is pulled up */
P1REN |= BUTTON_BIT; /* enable pull-up resistor */
is_button_down = 0;
}
/* Switches to next state of LED state machine */
static void trigger_led_sm(void)
{
switch (state) {
case RED_LIGHT:
state = NO_LIGHT_R;
P1OUT &= ~LED_RED_BIT;
break;
case NO_LIGHT_R:
state = GREEN_LIGHT;
P1OUT |= LED_GREEN_BIT;
break;
case GREEN_LIGHT:
state = NO_LIGHT_G;
P1OUT &= ~LED_GREEN_BIT;
break;
case NO_LIGHT_G:
state = RED_LIGHT;
P1OUT |= LED_RED_BIT;
break;
default:
/* Reset state machine */
init_leds();
break;
}
}
static void init(void)
{
init_leds();
init_button();
}
static void loop(void)
{
/* Button polling */
if (P1IN & BUTTON_BIT) { /* button is in released state */
if (is_button_down) {
is_button_down = 0;
/* event: button up */
}
} else { /* button is in pressed state */
if (!is_button_down) {
is_button_down = 1;
/* event: button down */
trigger_led_sm();
}
}
}
int main(void)
{
init();
for (;;)
loop();
return 0;
}
UPDATE
On schematic below you can see that "RST" pin and "P1.3" pin both have dedicated external pull-up resister: R27 for RST and R34 for P1.3. But if you have new revision of board -- R34 is not soldered there, so you have to use internal pull-up.
You can find complete schematics for your Launchpad here.
I am attempting to program two MSP430s to essentially instant message through PuTTY, but cannot figure out how to get typed information onto the MSP430 without the debugger. I'm using CCS and it's an MSP430 F2274. I have one program in which the user inputs in morse code on the button on one MSP430 that successfully outputs to PuTTY off another MSP430 via the following method.
void displayString(char array[], char size) {
WDTCTL = WDTPW + WDTHOLD; // Disable WDT
DCOCTL = CALDCO_8MHZ; // Load 8MHz constants
BCSCTL1 = CALBC1_8MHZ; //
P3SEL |= 0x30; // P3.4,5 = USCI_A0 TXD/RXD
UCA0CTL1 |= UCSSEL_2; // SMCLK
UCA0BR0 = 0x41; // 8MHz 9600
UCA0BR1 = 0x03; // 8MHz 9600
UCA0MCTL = UCBRS1; // Modulation UCBRSx = 2
UCA0CTL1 &= ~UCSWRST; // **Initialize USCI state
int count;
for(count=0; count<size; count++){
while (!(IFG2&UCA0TXIFG)); // USCI_A0 TX buffer ready?
UCA0TXBUF = array[count]; // TX -> RXed character
}
}
Can someone send code that does the reverse (types information onto MSP430) with a similar setup? thanks.
I used picocom:
$ picocom -r -b 9600 /dev/ttySxxxx
Code for UART initialization:
void uart_setup()
{
// Configure UART pins
P2SEL1 |= BIT0 + BIT1;
P2SEL0 &= ~(BIT0 + BIT1);
// Configure UART 0
UCA0CTL1 |= UCSWRST; // perform reset
UCA0CTL1 = UCSSEL_1; // Set ACLK = 32768 as UCBRCLK
UCA0BR0 = 3; // 9600 baud
UCA0BR1 = 0;
UCA0MCTLW |= 0x5300; // 32768/9600 - INT(32768/9600)=0.41
// UCBRSx value = 0x53 (See UG)
UCA0CTL1 &= ~UCSWRST; // release from reset
//UCA0IE |= UCRXIE; // Enable RX interrupt
}
Override putchar():
int putchar(int c)
{
if (c == '\n') putchar('\r');
while (!(UCA0IFG & UCTXIFG));
UCA0TXBUF = c;
return 0;
}
And then you can simple call printf(...) to output text from the MSP430 to the serial port.
If you still want to leave putchar() and prtinf() for debug purpose - printing into debug window of debugger, then you can have separate read function:
unsigned char ReadByteUCA_UART(void)
{
//while ((IFG2&UCA0RXIFG)==0); // wait for RX buffer (full)
while(UCA0STAT&UCBUSY);
return (UCA0RXBUF);
}