[ add comment ] | [ 0 trackbacks ] | permalink
MSP430
12 MSP430 Getting Started
MSP430 Polling
LaunchPad Introduction
14 MSP430 Architecture (Short version 44 pages) (Long version 871 pages)
MSP430 Assembly Programming
MSP430 C/C++ Programming
Last chance
for HW6-7
19 MSP430 Interrupts 8
26 MSP430 Timers and PWM
28 MSP430 Memory-mapped I/O
MSP430 Serial Communications
MSP430 C/Assembler comparison
3 Dec Review Bring LaunchPad and HW questions
Enrichment readings
Chapter 11. Windows Programming
Chapter 14. Disk Fundamentals.
Chapter 15. BIOS-Level Programming.
[ add comment ] | [ 0 trackbacks ] | permalink | related link
[ add comment ] | [ 0 trackbacks ] | permalink | related link
#!/usr/bin/python
# -*- coding: utf-8 -*-
import time
from decimal import Decimal
# debug on/off
DEBUG = True
# initial settings
twelfth_root_of_two = \
1.059463094359295264561825294946341700779204317494
root_016 = 1.0036166659754629134913855149569
root_032 = 1.0018067009036538249718210506931
root_064 = 1.0009029427989777995544424758581
root_100 = 1.0005777895065548592967925757932
root_128 = 1.0004513695322615727617341558255
# basic generator parameters
base_clock = 16000000 / 2 # 16Khz, but the real frequency is 1/2 (compl. cycle)
root_of_roots = root_032
# functions
def frequency_scaler(base_clock, desired_frequency):
''' base_clock in Hz, desired_frequency in Hz '''
base_clock = float(base_clock)
desired_frequency = float(desired_frequency)
common_denominator = base_clock / desired_frequency
best_effort_computation_round_error_frequency = base_clock
for interrupt_count in range(1, 65535):
timer_ticks = common_denominator // interrupt_count
if timer_ticks > 0 and timer_ticks < 65535 and \
(interrupt_count == 1 or interrupt_count == 2 or interrupt_count == 4 or interrupt_count == 8 \
or interrupt_count == 16 and ( interrupt_count > 18 or interrupt_count < 24 )):
computation_round_error_frequency = (base_clock / (interrupt_count * timer_ticks)) - desired_frequency
if abs(computation_round_error_frequency) < abs(best_effort_computation_round_error_frequency):
best_effort_computation_round_error_frequency = computation_round_error_frequency
selected_interrupt_count = interrupt_count
selected_timer_ticks = timer_ticks
return (selected_interrupt_count, int(selected_timer_ticks), round(best_effort_computation_round_error_frequency, 4))
def generate_subsequent(f):
''' generate base and all the subsequent
frequencies for a given (semi)tone
'''
global note_index
current_frequency = f
note_in_sequence = 0
while note_in_sequence != steps_to_next_note:
(interrupt_count, timer_ticks, error) = frequency_scaler(base_clock, current_frequency)
interrupt_count_dict[note_index] = interrupt_count
timer_ticks_dict[note_index] = timer_ticks
print 'ix: %s/%s, f: %s, midinote: %s, octave: %s, note: %s, intr_count: %s, time_ticks: %s, error: %s' \
% (
note_in_sequence,
note_index,
current_frequency,
midi_note,
octave,
note,
interrupt_count,
timer_ticks,
error
)
if current_frequency == f:
pass
# time.sleep(5)
current_frequency *= root_of_roots
note_index += 1
note_in_sequence += 1
# init variables
interrupt_count_dict = {}
timer_ticks_dict = {}
# note defaults
notes = [
'C ',
'Db',
'D ',
'Eb',
'E ',
'F ',
'Gb',
'G ',
'Ab',
'A ',
'Bb',
'B ',
]
start_tone_frequency = 8.1758 # C0
start_midi_note = 0
steps_to_next_note = 32
f = start_tone_frequency
midi_note = start_midi_note
note_index = 0
# generate frequencies
# one (semi)tone below for down tuning (-offset tuning)
octave = 0
note = 'B '
midi_note = -1
generate_subsequent(start_tone_frequency / twelfth_root_of_two)
midi_note += 1
# generate the rest (along with a +offset tuning)
try:
for octave in xrange(0, 11):
for note in notes:
print '------------- note: %s %s -----------------' \
% (note, octave)
generate_subsequent(f)
midi_note += 1
f *= twelfth_root_of_two
if midi_note > 127:
raise ValueError
except ValueError:
pass
# list computed results
print '>> interrupt counts:'
for nr in xrange(1, len(interrupt_count_dict)):
print '%s, ' % int(interrupt_count_dict[nr]),
print '>> timer ticks:'
for nr in xrange(1, len(interrupt_count_dict)):
print '%s, ' % int(timer_ticks_dict[nr]),
print '>> dictionary sizes:'
print ">> timer_ticks_dict has: %s items" % (len(timer_ticks_dict) - 1 )
print ">> interrupt_count_dict has: %s items" % (len(interrupt_count_dict) - 1 )
[ add comment ] | [ 0 trackbacks ] | permalink
The controller message has an argument that goes from -8192 to 8191 and in standard MIDI files this is supposed to cover the range from -200 cent to 200 cent, where 1 cent is 1/100 of semitone, i.e. a ratio of 2^(1/1200) = 1.000577789506555.
[ add comment ] | [ 0 trackbacks ] | permalink | related link
static int state = 0;
So if you need a variable that is only used within a function and only updated by that function and you need the value of that variable to remain for the next time that you call the function then you need to define it as a static variable.
[ add comment ] | [ 0 trackbacks ] | permalink
In many application, it is sometime necessary to place a variable in a specific memory location. This wiki shows a small guide to implement the specific variable placement for C programming language using most common compilers/IDEs for MSP430.
[ add comment ] | [ 0 trackbacks ] | permalink | related link
/*
* TA0CCTL0, Capture/Compare Control Register 0
*
* CM_1 -- Rising Edge
* CCIS_0 -- CCIxA
* ~SCS -- Asynchronous Capture
* ~SCCI -- Latched capture signal (read)
* ~CAP -- Compare mode
* OUTMOD_0 -- PWM output mode: 0 - OUT bit value
*
* Note: ~<BIT> indicates that <BIT> has value zero
*/
TA0CCTL0 = CM_1 | CCIS_0 | OUTMOD_0 | CCIE;
/* TA0CCR0, Timer_A Capture/Compare Register 0 */
TA0CCR0 = 31;
/*
* TA0CTL, Timer_A3 Control Register
*
* TASSEL_0 -- TACLK
* ID_0 -- Divider - /1
* MC_1 -- Up Mode
*/
TA0CTL = TASSEL_0 | ID_0 | MC_1;
[ add comment ] | [ 0 trackbacks ] | permalink
TIMER0_A1_VECTOR handles all Timer A0 interrupts except CCR0. TIMER0_A0_VECTOR handles the CCR0 interrupt.
Code for the TIMER0_A1_VECTOR should read TA0IV to clear the source of the interrupt (and perhaps decode it when multiple sources are enabled).
Code for the TIMER0_A0_VECTOR doesn't need to clear the source of its interrupt because the hardware automatically clears the single source.
/*
* ======== Timer0_A3 Interrupt Service Routine ========
*/
#pragma vector=TIMER0_A1_VECTOR
__interrupt void TIMER0_A1_ISR_HOOK(void)
{
/* USER CODE START (section: TIMER0_A1_ISR_HOOK) */
switch( TAIV ) {
case 2:
P1OUT ^= BIT0; /* Toggle LED on P1.0 */
break; // CCR1 not used
case 4: break; // CCR2 not used
case 10: break; // overflow break; }
}
/* USER CODE END (section: TIMER0_A1_ISR_HOOK) */
}
#pragma vector = TIMER0_A1_VECTOR
__interrupt void TIMER0_A1_ISR()
{
switch (__even_in_range(TA0IV, TA0IV_TAIFG)) // recommended syntax for TAIV handling
{
case TA0IV_TACCR1: // CCR1
count1++;
if (count1 == 25)
{
P1OUT ^= 0X01;
count1 = 0;
}
break;
case TA0IV_TACCR2: // CCR2 - unused
case TA0IV_6: // Reserved
case TA0IV_8: // Reserved
case TA0IV_TAIFG: // Timer overflow - unused
break;
}
}
The MSP430 uses various clock sources from external XTAL's and internal oscillators such as the DCO (Digital Control Oscillator), VLO (Very low frequency Oscillator) etc to generate 3 internal clock sources.
-------------------------------------------
internal clocks (ACLK, SMCLK)
ACLK (TACLK/ACKL)
The ACLK clock can be sourced from the external 32 KHz XTAL or internal 10 KHz VLO Oscillator.
SMCLK
Usually sourced from the MCLK
(MCLK Can be sourced from the external High frequency XTAL or internal DCO)
-------------------------------------------
external clocks ()
The above is general however other possibities exist and differ from device to device. Newer 5x parts have many more clocking options.
The timers on the MSP430 can be clocked from various internal clocks such as the ACLK, SMCLK etc. These can be divided down if required. The TACLK is an external pin that can be used to clock the internal timer.
[ add comment ] | [ 0 trackbacks ] | permalink | related link
http://www.ti.com/ww/en/launchpad/launchpad.html
[ 1 comment ] ( 6 views ) | [ 0 trackbacks ] | permalink | related link