How can I use an older version's CCS header file? - c

I am trying to include "msp.h" in a CCS v9 project in order to run code in a book I am reading. Here's an example code snippet:
* This program toggles green LED for 0.5 second ON and 0.5 second OFF.
* The green LED is connected to P2.1.
* The LEDs are high active (a '1' turns ON the LED).
*
* Tested with Keil 5.20 and MSP432 Device Family Pack V2.2.0
* on XMS432P401R Rev C.
*/
#include "msp.h"
void delayMs(int n);
int main(void) {
P2->SEL1 &= ~2; /* configure P2.1 as simple I/O */
P2->SEL0 &= ~2;
P2->DIR |= 2; /* P2.1 set as output pin */
while (1) {
P2->OUT |= 2; /* turn on P2.1 green LED */
delayMs(500);
P2->OUT &= ~2; /* turn off P2.1 green LED */
delayMs(500);
}
}
/* delay milliseconds when system clock is at 3 MHz for Rev C MCU */
void delayMs(int n) {
int i, j;
for (j = 0; j < n; j++)
for (i = 750; i > 0; i--); /* Delay 1 ms*/
}
It appears that it needs the msp.h include file to run, but I haven't been able to find the specific header file anywhere in the resource explorer when searching through the msp432 libraries. Any info on how to get this to compile would be great!
Thank you!

You could throw it into the CCS cloud editor likely. Make a new project for your device and copy and paste the code there. It's generally pretty proficient at finding headers.
The basic cycle for stuff like this on the local editor is:
Make sure the development files for the device is installed
Figure out where those files are hiding
Dig through files until you find the header
Go into properties of your project and under compiler options add the folder
What may also help is to make sure you have the MSP432 stuff installed, import it's blinky led example project and see what it's include options are. Or even just modify that newly imported project with this code.
Sorry this isn't a step by step. I'm not on my computer with CCS right now.

Related

Question about Peripheral Timing Generator (PTG) Module on dsPIC33CK256MP508

I am a newbie to programming in the Microchip PIC environment, so please excuse my naivete! I recently began experimenting with the dsPIC33CK Curiosity dev board (which contains the dsPIC33CK256MP508 dsp/mcu at its core), and have been exploring the on-board modules, like direct memory access (DMA) and the peripheral trigger generator (PTG).
DMA is working, but I am having trouble with a seemingly-simple PTG task, and I was wondering if anyone has any ideas -- the task involves a simple external interrupt/trigger to the PTG, which then needs to trigger another external pin to go logic-high.
In real life, an incoming logic-high signal will indicate the start of a series of analog data to be read, so the outgoing signal will (repeatedly) trigger an external ADC. I am using an external ADC (an ADS831, which I have working well) since the internal ADC in the dsPIC33 does not sample at the rates I need.
I am unsure if my mistake lies with my PTG commands, or if maybe my Peripheral Pin Select (PPS) module setup is flawed. Unfortunately, it appears that the builtin IO pin unlocking function ("__builtin_write_RPCON()") is undefined, at least with my included libraries. So, fell back on in-line assembler to perform the unlock sequence (detailed in datasheet DS70005349J-page 132).
Also strange: you'll notice I start my PTG sequence on "STEP3", though the PTG documentation (e.g., DS70000669B-page 33) advises starting at "STEP0". The reason I've done this is because "STEP1" and "STEP2" are apparently used by more than one Special Function Register (SFR). I discovered this in a support file included in my compiler directory (specifically, lines 26278 and 26281 of file "p33CK256MP508.h").
Anyway, here is my simple PTG-testbed code:
/* Testbed to explore the PTG module.
*
* File: newmain.c
* Author: benjamin sadler
*
* Created on January 26, 2023, 11:43 AM
*/
#include <xc.h>
/*
#define PTGCTRL(x) ((0x0 << 4) | ((x) & 0x0F)) // PTG command definitions
#define PTGWHI(x) ((0x4 << 4) | ((x) & 0x0F)) // from DS70000669B-page 15
#define PTGTRIG(x) ((0x4 << 5) | ((x) & 0x1F)) // (currently commented to
#define PTGJMPC0(x) ((0x6 << 5) | ((x) & 0x1F)) // try alternate commands
*/ // (see lines 58-60))
void init_PTG(void); // init function primitives
void init_PPS(void);
int main(int argc, char** argv) {
ANSELB = 0x0; // configure PORTB and PORTC
ANSELC = 0x0; // as digital, and set
TRISBbits.TRISB15 = 0; // direction bits:
TRISCbits.TRISC0 = 1; // B15->out, C0->in
init_PPS(); // initialize PPS
init_PTG(); // initialize PTG
PTGCSTbits.PTGSTRT = 1; // start PTG ...
while(1); // .. and wait for INT2->high.
return (1);
}
void init_PPS( void )
{
INTCON2bits.GIE = 1; // enable global interrupts
asm ("mov #0x55, w0"); // "__builtin_write_RPCON()"
asm ("mov w0, _NVMKEY"); // function doesn't appear
asm ("mov #0xAA, w0"); // to be defined, so in-line
asm ("mov w0, _NVMKEY"); // assembly needed unlock IOLOCK
RPCONbits.IOLOCK = 0; // (that is, set IOLOCK = 0)
_INT2R = 48; // PPS connect INT2 with RP48/PORTC0
asm ("mov #0x55, w0"); // more in-line assembly to
asm ("mov w0, _NVMKEY"); // re-lock IOLOCK ...
asm ("mov #0xAA, w0");
asm ("mov w0, _NVMKEY");
RPCONbits.IOLOCK = 1; // re-lock IOLOCK
}
void init_PTG( void )
{
PTGCON = 0; // most bits on PTGCST and
PTGCST = 0; // PTGCST registers should be
PTGCSTbits.PTGEN = 1; // zero, except PTGEN=1 which
// enables module
PTGQPTR = 3; // start at STEP3 (STEP1, STEP2
// aren't available??)
PTGC0LIM = 5; // loop 5 times back to STEP3
/* // set STEP commands:
_STEP3 = PTGWHI(15); // wait for INT2 interrupt
_STEP4 = PTGTRIG(25); // then trigger RP47/B14 high
_STEP5 = PTGJMPC0(3); // and jump back to STEP3
*/
_STEP3 = 0b01001111; // alternate try at setting
_STEP4 = 0b10011001; // PTG step commands, using
_STEP5 = 0b11000011; // data from Table 24-1 in
} // datasheet DS70005349J-page 478
And here are the results I'm getting:
Using the simulator (MPLAB X IDE v6.05, with xc16 compiler v2.00) with the correct device (dsPIC33CK256MP508) selected, this code will compile and run, but when I feed in a simulated RC0-> high with the Stimulus tool, I can see that PORTC0 goes high in the variable watch window, but the PTG-triggered output (on RP47/PORTB15) is never observed.
B15 stays low :(
You can also see I've tried programming the PTG steps both using the suggested bit-wise operators (currently commented out), as well as manually loading the bit fields.
I have worked on this for several days without any success, and now I humbly ask for help!

ws2812b on ATTiny85

I have ATTiny with 1MHz clock. I'm trying to light up some ws2812b led strip. I conected everything without any resistors and capacitors. I think everything should works but it doesn't :)
I'm useing light_ws2812 library https://github.com/cpldcpu/light_ws2812.
Below is example code. I have hanged only F_CPU frequency, numper of output pin and reset time in config file. Could You help me find the problem and advice how can I fix it?
MAIN
#define F_CPU 1000000
#include <util/delay.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include "ws2812_config.h"
#include "light_ws2812.h"
struct cRGB led[2];
int main(void)
{
uint8_t pos=0;
uint8_t direction=1;
uint8_t i;
#ifdef __AVR_ATtiny10__
CCP=0xD8; // configuration change protection, write signature
CLKPSR=0; // set cpu clock prescaler =1 (8Mhz) (attiny 4/5/9/10)
#endif
led[0].r=255;led[0].g=00;led[0].b=00; // LED 0 is red
led[1].r=255;led[1].g=16;led[1].b=16; // LED 1 is White
while(1)
{
for (i=0; i<pos; i++)
ws2812_sendarray((uint8_t *)&led[0],3); // Repeatedly send "red" to the led string.
// No more than 1-2µs should pass between calls
// to avoid issuing a reset condition.
for (i=0; i<(16-pos); i++)
ws2812_sendarray((uint8_t *)&led[1],3); // white
_delay_ms(50); // Issue reset and wait for 50 ms.
pos+=direction;
if ((pos==16)||(pos==0)) direction=-direction;
}
}
CONFIG
/*
* light_ws2812_config.h
*
* v2.4 - Nov 27, 2016
*
* User Configuration file for the light_ws2812_lib
*
*/
#ifndef WS2812_CONFIG_H_
#define WS2812_CONFIG_H_
///////////////////////////////////////////////////////////////////////
// Define Reset time in µs.
//
// This is the time the library spends waiting after writing the data.
//
// WS2813 needs 300 µs reset time
// WS2812 and clones only need 50 µs
//
///////////////////////////////////////////////////////////////////////
#define ws2812_resettime 50
///////////////////////////////////////////////////////////////////////
// Define I/O pin
///////////////////////////////////////////////////////////////////////
#define ws2812_port B // Data port
#define ws2812_pin 3 // Data out pin
#endif /* WS2812_CONFIG_H_ */
I think 1Mhz is just too slow to be able to generate the signals required by the WS2812B.
The most timing critical WS2812B signal - the TH0 pulse - must be less than 500ns wide, and at 1Mhz, each MCU cycle is 1000ns.
More info on the the WS2812B timing constraints here...
https://wp.josh.com/2014/05/13/ws2812-neopixels-are-not-so-finicky-once-you-get-to-know-them/
Series resistors and parallel capacitors do help decrease noise that causes inexplicable behavior. But you're right, it should not stop the WS2812bs from working completely.
I suggest you try another pin on your attiny. Pin 3 is used for usb communication. If you are powering your attiny through a usb cable connected to your computer this will cause trouble. Try pins 5 and 6 for example.
You can try the Adafruit_NeoPixel library. I tried and it compiled for attiny85 without modification. I did not actually try to run it since I do not have an attiny lying around.
Also, some of the cheaper WS2812b ledstrips that are around on ebay got their Din and Dout labels switched. This means you have to connect the Dout pin to your attiny. This has actually happened to me once.
I don't know about pulse lenghts in WS2812bs but if that is not the issue I'm pretty sure it's one of the three I mentioned above.
Hope that helps.
[Solution]
According to README I've included config file before header in my MAIN source code file. It was a mistake because the two files are part of different compilation units and DEFINEs are not shared between them. It causes that my configuration settings was ignored and program used default (not correct in my case) ones.
To fix this bug You should include Your ws2812_config.h within light_ws2812.h
You should use the library FASTLED,you can download it on arduino ide .It's very easy to light WS2812 with ATTINY85 by using this library.

Serial Communication Using C

I'm trying to read the on board temp sensor of the msp430fr5739 micro controller and display the results in a terminal.
using C the task should be accomplished!!!
All the code and custom libraries can be found on GitHub
My operating system is ubuntu and the IDE I'm using is code composer studio
here is the main.c
#include <msp430fr5739.h>
#include "system.h"
#include "temp.h"
#include "uart.h"
/*
main.c
1. Switches and LEDs
2.
3. Temp sens
*/
int main(void) {
WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timer
unsigned int tempVal = 0; // temp readings
LEDs_INIT(); // Init leds
SWITCHEs_INIT(); // Init Switches
serialBegin(); // Begin Serial communication at 9600 buad
while (1)
{
__bis_SR_register(LPM4_bits + GIE); // Enter LPM4 with interrupts enabled
tempVal = getThermisterVal();
}
return 0;
}
I've tried to follow the demo code that TI had shipped with the board and the resulting libs are published on GitHub (I didn't post all the lib and code, simply because it's too long)
Now I'm really struggling with the serial communication part, i know that the bytes sent from the micro-controller has to be read by some sort of serial monitor application on PC.
Any help is appreciated.

Program Working on Old Device and New Device's Simulator but not on New Device

I'm hitting a roadblock in porting over a program I previously wrote for the PIC10F200 (see this related SO question). Turns out another component on the board needed to be swapped out for something that needed to be communicated with through I2C, so ergo, I'm porting the program to the PIC12LF1552.
This is how the program currently works (at least on the PIC10F200)
Program starts at IDLE (no lights on)
Press the button, the T0CKI pin (in the PIC12LF1552's case, RA2) is already pulled up to VDD (~3.3V) by an external pull-up resistor, the button is connected to ground and the pin, ergo pulling T0CKI's signal to LO.
TMR0 increments (supposedly)
After a time period where PORTAbits.RA2 settles, state increments
switch block moves to turn the external LED on, in the previous version of the circuit, this would also activate the IC this pin is connected to.
Rinse repeat for the other 3 states.
I have re-verified this functionality through using MPLAB X's simulator where I fired T0CKI (again, configured as RA2, again confirmed by the simulator) to HI and then to LO to engage the TMR0 code. state increments, and everybody is happy.
When I program the device using either MPLAB X connected to my PICkit3 or the included standalone programmer MPLAB IPE, the program does not work as intended. I have re-verified all connections, the programming port is connected as it should be. The button is attached the right pin. The test LED is attached to the right pin. For the time being we are not considering any I2C communication, I just want to see my status LED (RA4) toggle.
I know that now that I've transitioned to a midrange PIC, I can use the interrupt features, but for the time being I want to get what I know has worked on a much simpler device working on the current one.
My question then is, why doesn't this program work when programmed to the PIC12LF1552, but yet works on the PIC12LF1552 simulator AND its previous incarnation worked on the PIC10F200 (both programmed and simulated)?
Thanks in advance everyone!
The following is the entire program:
#if defined(__XC)
#include <xc.h> /* XC8 General Include File */
#endif
#include <stdint.h> /* For uint8_t definition */
#include <stdbool.h> /* For true/false definition */
#include <stdio.h>
#include <stdlib.h>
/******************************************************************************/
/* Defines */
/******************************************************************************/
//#define SYS_FREQ 16000000L
//#define FCY SYS_FREQ/4
#define _XTAL_FREQ 500000
__CONFIG
(
MCLRE_ON &
CP_OFF &
BOREN_OFF &
WDTE_OFF &
PWRTE_OFF &
FOSC_INTOSC
);
void main(void)
{
TRISA = 0b101111;
OPTION_REG = 0b01111111;
APFCONbits.SDSEL = 1;
unsigned char state = 0;
unsigned char count = 0;
while(1)
{
switch (state)
{
case 0: // IDLE/OFF
if (LATAbits.LATA4) LATAbits.LATA4 = 0;
break;
case 1: // ON
if (!LATAbits.LATA4) LATAbits.LATA4 = 1;
break;
case 2: // BLINK (slow)
LATAbits.LATA4 = !LATAbits.LATA4;
__delay_ms(100);
break;
case 3: // BLINK (fast)
LATAbits.LATA4 = !LATAbits.LATA4;
__delay_ms(50);
break;
case 4: // BEAT DETECT
LATAbits.LATA4 = LATAbits.LATA5;
break;
default:
state = 0;
break;
}
if (TMR0 > 0)
{
while (count < 20)
{
if (!PORTAbits.RA2) count = 0;
__delay_ms(10);
count++;
}
TMR0 = 0;
state++;
}
}
}
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.
I do not see any configuration bit setup in your code.
Setting ANSEL and ANSELH to 0 should do the trick.
According to the this documentation , on page 93 about the ANSELA register
"The ANSELA bits default to the Analog mode after Reset. To use any
pins as digital general purpose or peripheral inputs, the
corresponding ANSEL bits must be initialized to ‘0’ by user software."
If you don't plan to use analog inputs, you may add something like ANSELA=0;

Writing Device Drivers for Microcontrollers, where to define IO Port pins?

I always seem to encounter this dilemma when writing low level code for MCU's.
I never know where to declare pin definitions so as to make the code as reusable as possible.
In this case Im writing a driver to interface an 8051 to a MCP4922 12bit serial DAC.
Im unsure how/where I should declare the pin definitions for The CS(chip select) and LDAC(data latch) for the DAC. At the moment there declared in the header file for the driver.
Iv done a lot of research trying to figure out the best approach but havent really found anything.
Im basically want to know what the best practices... if there are some books worth reading or online information, examples etc, any recommendations would be welcome.
Just a snippet of the driver so you get the idea
/**
#brief This function is used to write a 16bit data word to DAC B -12 data bit plus 4 configuration bits
#param dac_data A 12bit word
#param ip_buf_unbuf_select Input Buffered/unbuffered select bit. Buffered = 1; Unbuffered = 0
#param gain_select Output Gain Selection bit. 1 = 1x (VOUT = VREF * D/4096). 0 =2x (VOUT = 2 * VREF * D/4096)
*/
void MCP4922_DAC_B_TX_word(unsigned short int dac_data, bit ip_buf_unbuf_select, bit gain_select)
{
unsigned char low_byte=0, high_byte=0;
CS = 0; /**Select the chip*/
high_byte |= ((0x01 << 7) | (0x01 << 4)); /**Set bit to select DAC A and Set SHDN bit high for DAC A active operation*/
if(ip_buf_unbuf_select) high_byte |= (0x01 << 6);
if(gain_select) high_byte |= (0x01 << 5);
high_byte |= ((dac_data >> 8) & 0x0F);
low_byte |= dac_data;
SPI_master_byte(high_byte);
SPI_master_byte(low_byte);
CS = 1;
LDAC = 0; /**Latch the Data*/
LDAC = 1;
}
This is what I did in a similar case, this example is for writing an I²C driver:
// Structure holding information about an I²C bus
struct IIC_BUS
{
int pin_index_sclk;
int pin_index_sdat;
};
// Initialize I²C bus structure with pin indices
void iic_init_bus( struct IIC_BUS* iic, int idx_sclk, int idx_sdat );
// Write data to an I²C bus, toggling the bits
void iic_write( struct IIC_BUS* iic, uint8_t iicAddress, uint8_t* data, uint8_t length );
All pin indices are declared in an application-dependent header file to allow quick overview, e.g.:
// ...
#define MY_IIC_BUS_SCLK_PIN 12
#define MY_IIC_BUS_SCLK_PIN 13
#define OTHER_PIN 14
// ...
In this example, the I²C bus implementation is completely portable. It only depends on an API that can write to the chip's pins by index.
Edit:
This driver is used like this:
// main.c
#include "iic.h"
#include "pin-declarations.h"
main()
{
struct IIC_BUS mybus;
iic_init_bus( &mybus, MY_IIC_BUS_SCLK_PIN, MY_IIC_BUS_SDAT_PIN );
// ...
iic_write( &mybus, 0x42, some_data_buffer, buffer_length );
}
In one shop I worked at, the pin definitions were put into a processor specific header file. At another shop, I broke the header files into themes associated with modules in the processor, such as DAC, DMA and USB. A master include file for the processor included all of these themed header files. We could model different varieties of the same processor by include different module header files in the processor file.
You could create an implementation header file. This file would define I/O pins in terms of the processor header file. This gives you one layer of abstraction between your application and the hardware. The idea is to loosely couple the application from hardware as much as possible.
If only the driver needs to know about the CS pin, then the declaration should not appear in the header, but within the driver module itself. Code re-use is best served by hiding data at the most restrictive scope possible.
In the event that an external module needs to control CS, add an access function to the device driver module so that you have single point control. This is useful if during debugging you need to know where and when an I/O pin is being asserted; you only have one point to apply instrumentation or breakpoints.
The answer with the run-time configuration will work for a decent CPU like ARM, PowerPC...but the author is running a 8051 here. #define is probably the best way to go. Here's how I would break it down:
blah.h:
#define CSN_LOW() CS = 0
#define CSN_HI() CS = 1
#define LATCH_STROBE() \
do { LDAC = 0; LDAC = 1; } while (0)
blah.c:
#include <blah.h>
void blah_update( U8 high, U8 low )
{
CSN_LOW();
SPI_master_byte(high);
SPI_master_byte(low);
CSN_HI();
LATCH_STROBE();
}
If you need to change the pin definition, or moved to a different CPU, it should be obvious where you need to update. And it's also helps when you have to adjust the timing on the bus (ie. insert a delay here and there) as you don't need to change all over the place. Hope it helps.

Resources